2020-01-12 15:11:17 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-01-12 15:11:17 +03:00
package repository
import (
"bytes"
2021-09-23 18:45:36 +03:00
"context"
2020-01-12 15:11:17 +03:00
"fmt"
"os"
"path/filepath"
2022-03-29 10:23:45 +03:00
"sort"
2020-01-12 15:11:17 +03:00
"strings"
"time"
2022-06-13 12:37:59 +03:00
issues_model "code.gitea.io/gitea/models/issues"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2020-01-12 15:11:17 +03:00
"code.gitea.io/gitea/modules/git"
2023-03-02 02:44:23 +03:00
"code.gitea.io/gitea/modules/label"
2020-01-12 15:11:17 +03:00
"code.gitea.io/gitea/modules/log"
2022-03-29 10:23:45 +03:00
"code.gitea.io/gitea/modules/options"
2020-06-17 23:53:55 +03:00
"code.gitea.io/gitea/modules/setting"
2022-04-01 11:47:50 +03:00
"code.gitea.io/gitea/modules/templates/vars"
2020-08-11 23:05:34 +03:00
"code.gitea.io/gitea/modules/util"
2021-12-10 11:14:24 +03:00
asymkey_service "code.gitea.io/gitea/services/asymkey"
2020-01-12 15:11:17 +03:00
)
2023-04-10 11:44:02 +03:00
type OptionFile struct {
DisplayName string
Description string
}
2022-03-29 10:23:45 +03:00
var (
// Gitignores contains the gitiginore files
Gitignores [ ] string
// Licenses contains the license files
Licenses [ ] string
// Readmes contains the readme files
Readmes [ ] string
2023-04-10 11:44:02 +03:00
// LabelTemplateFiles contains the label template files, each item has its DisplayName and Description
LabelTemplateFiles [ ] OptionFile
labelTemplateFileMap = map [ string ] string { } // DisplayName => FileName mapping
2022-03-29 10:23:45 +03:00
)
2023-04-10 11:44:02 +03:00
type optionFileList struct {
all [ ] string // all files provided by bindata & custom-path. Sorted.
custom [ ] string // custom files provided by custom-path. Non-sorted, internal use only.
}
// mergeCustomLabelFiles merges the custom label files. Always use the file's main name (DisplayName) as the key to de-duplicate.
func mergeCustomLabelFiles ( fl optionFileList ) [ ] string {
exts := map [ string ] int { "" : 0 , ".yml" : 1 , ".yaml" : 2 } // "yaml" file has the highest priority to be used.
m := map [ string ] string { }
merge := func ( list [ ] string ) {
sort . Slice ( list , func ( i , j int ) bool { return exts [ filepath . Ext ( list [ i ] ) ] < exts [ filepath . Ext ( list [ j ] ) ] } )
for _ , f := range list {
m [ strings . TrimSuffix ( f , filepath . Ext ( f ) ) ] = f
}
}
merge ( fl . all )
merge ( fl . custom )
files := make ( [ ] string , 0 , len ( m ) )
for _ , f := range m {
files = append ( files , f )
}
sort . Strings ( files )
return files
}
2022-03-29 10:23:45 +03:00
// LoadRepoConfig loads the repository config
2023-04-10 11:44:02 +03:00
func LoadRepoConfig ( ) error {
types := [ ] string { "gitignore" , "license" , "readme" , "label" } // option file directories
typeFiles := make ( [ ] optionFileList , len ( types ) )
2022-03-29 10:23:45 +03:00
for i , t := range types {
2023-04-10 11:44:02 +03:00
var err error
2023-04-12 13:16:45 +03:00
if typeFiles [ i ] . all , err = options . AssetFS ( ) . ListFiles ( t , true ) ; err != nil {
2023-04-10 11:44:02 +03:00
return fmt . Errorf ( "failed to list %s files: %w" , t , err )
2022-03-29 10:23:45 +03:00
}
2023-04-10 11:44:02 +03:00
sort . Strings ( typeFiles [ i ] . all )
customPath := filepath . Join ( setting . CustomPath , "options" , t )
if isDir , err := util . IsDir ( customPath ) ; err != nil {
return fmt . Errorf ( "failed to check custom %s dir: %w" , t , err )
} else if isDir {
if typeFiles [ i ] . custom , err = util . StatDir ( customPath ) ; err != nil {
return fmt . Errorf ( "failed to list custom %s files: %w" , t , err )
2023-03-02 02:44:23 +03:00
}
}
2022-03-29 10:23:45 +03:00
}
2023-04-10 11:44:02 +03:00
Gitignores = typeFiles [ 0 ] . all
Licenses = typeFiles [ 1 ] . all
Readmes = typeFiles [ 2 ] . all
2022-03-29 10:23:45 +03:00
// Load label templates
2023-04-10 11:44:02 +03:00
LabelTemplateFiles = nil
labelTemplateFileMap = map [ string ] string { }
for _ , file := range mergeCustomLabelFiles ( typeFiles [ 3 ] ) {
description , err := label . LoadTemplateDescription ( file )
2022-03-29 10:23:45 +03:00
if err != nil {
2023-04-10 11:44:02 +03:00
return fmt . Errorf ( "failed to load labels: %w" , err )
2022-03-29 10:23:45 +03:00
}
2023-04-10 11:44:02 +03:00
displayName := strings . TrimSuffix ( file , filepath . Ext ( file ) )
labelTemplateFileMap [ displayName ] = file
LabelTemplateFiles = append ( LabelTemplateFiles , OptionFile { DisplayName : displayName , Description : description } )
2022-03-29 10:23:45 +03:00
}
// Filter out invalid names and promote preferred licenses.
sortedLicenses := make ( [ ] string , 0 , len ( Licenses ) )
for _ , name := range setting . Repository . PreferredLicenses {
Improve utils of slices (#22379)
- Move the file `compare.go` and `slice.go` to `slice.go`.
- Fix `ExistsInSlice`, it's buggy
- It uses `sort.Search`, so it assumes that the input slice is sorted.
- It passes `func(i int) bool { return slice[i] == target })` to
`sort.Search`, that's incorrect, check the doc of `sort.Search`.
- Conbine `IsInt64InSlice(int64, []int64)` and `ExistsInSlice(string,
[]string)` to `SliceContains[T]([]T, T)`.
- Conbine `IsSliceInt64Eq([]int64, []int64)` and `IsEqualSlice([]string,
[]string)` to `SliceSortedEqual[T]([]T, T)`.
- Add `SliceEqual[T]([]T, T)` as a distinction from
`SliceSortedEqual[T]([]T, T)`.
- Redesign `RemoveIDFromList([]int64, int64) ([]int64, bool)` to
`SliceRemoveAll[T]([]T, T) []T`.
- Add `SliceContainsFunc[T]([]T, func(T) bool)` and
`SliceRemoveAllFunc[T]([]T, func(T) bool)` for general use.
- Add comments to explain why not `golang.org/x/exp/slices`.
- Add unit tests.
2023-01-11 08:31:16 +03:00
if util . SliceContainsString ( Licenses , name , true ) {
2022-03-29 10:23:45 +03:00
sortedLicenses = append ( sortedLicenses , name )
}
}
for _ , name := range Licenses {
Improve utils of slices (#22379)
- Move the file `compare.go` and `slice.go` to `slice.go`.
- Fix `ExistsInSlice`, it's buggy
- It uses `sort.Search`, so it assumes that the input slice is sorted.
- It passes `func(i int) bool { return slice[i] == target })` to
`sort.Search`, that's incorrect, check the doc of `sort.Search`.
- Conbine `IsInt64InSlice(int64, []int64)` and `ExistsInSlice(string,
[]string)` to `SliceContains[T]([]T, T)`.
- Conbine `IsSliceInt64Eq([]int64, []int64)` and `IsEqualSlice([]string,
[]string)` to `SliceSortedEqual[T]([]T, T)`.
- Add `SliceEqual[T]([]T, T)` as a distinction from
`SliceSortedEqual[T]([]T, T)`.
- Redesign `RemoveIDFromList([]int64, int64) ([]int64, bool)` to
`SliceRemoveAll[T]([]T, T) []T`.
- Add `SliceContainsFunc[T]([]T, func(T) bool)` and
`SliceRemoveAllFunc[T]([]T, func(T) bool)` for general use.
- Add comments to explain why not `golang.org/x/exp/slices`.
- Add unit tests.
2023-01-11 08:31:16 +03:00
if ! util . SliceContainsString ( setting . Repository . PreferredLicenses , name , true ) {
2022-03-29 10:23:45 +03:00
sortedLicenses = append ( sortedLicenses , name )
}
}
Licenses = sortedLicenses
2023-04-10 11:44:02 +03:00
return nil
2022-03-29 10:23:45 +03:00
}
2022-08-25 05:31:57 +03:00
func prepareRepoCommit ( ctx context . Context , repo * repo_model . Repository , tmpDir , repoPath string , opts CreateRepoOptions ) error {
2020-01-12 15:11:17 +03:00
commitTimeStr := time . Now ( ) . Format ( time . RFC3339 )
authorSig := repo . Owner . NewGitSig ( )
// Because this may call hooks we should pass in the environment
env := append ( os . Environ ( ) ,
"GIT_AUTHOR_NAME=" + authorSig . Name ,
"GIT_AUTHOR_EMAIL=" + authorSig . Email ,
"GIT_AUTHOR_DATE=" + commitTimeStr ,
"GIT_COMMITTER_NAME=" + authorSig . Name ,
"GIT_COMMITTER_EMAIL=" + authorSig . Email ,
"GIT_COMMITTER_DATE=" + commitTimeStr ,
)
// Clone to temporary path and do the init commit.
2022-10-23 17:44:45 +03:00
if stdout , _ , err := git . NewCommand ( ctx , "clone" ) . AddDynamicArguments ( repoPath , tmpDir ) .
2020-01-12 15:11:17 +03:00
SetDescription ( fmt . Sprintf ( "prepareRepoCommit (git clone): %s to %s" , repoPath , tmpDir ) ) .
2022-04-01 05:55:30 +03:00
RunStdString ( & git . RunOpts { Dir : "" , Env : env } ) ; err != nil {
2020-01-12 15:11:17 +03:00
log . Error ( "Failed to clone from %v into %s: stdout: %s\nError: %v" , repo , tmpDir , stdout , err )
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "git clone: %w" , err )
2020-01-12 15:11:17 +03:00
}
// README
2023-03-08 12:31:27 +03:00
data , err := options . Readme ( opts . Readme )
2020-01-12 15:11:17 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "GetRepoInitFile[%s]: %w" , opts . Readme , err )
2020-01-12 15:11:17 +03:00
}
cloneLink := repo . CloneLink ( )
match := map [ string ] string {
"Name" : repo . Name ,
"Description" : repo . Description ,
"CloneURL.SSH" : cloneLink . SSH ,
"CloneURL.HTTPS" : cloneLink . HTTPS ,
2020-04-07 04:40:38 +03:00
"OwnerName" : repo . OwnerName ,
2020-01-12 15:11:17 +03:00
}
2022-04-01 11:47:50 +03:00
res , err := vars . Expand ( string ( data ) , match )
if err != nil {
// here we could just log the error and continue the rendering
log . Error ( "unable to expand template vars for repo README: %s, err: %v" , opts . Readme , err )
}
2021-09-22 08:38:34 +03:00
if err = os . WriteFile ( filepath . Join ( tmpDir , "README.md" ) ,
2022-04-01 11:47:50 +03:00
[ ] byte ( res ) , 0 o644 ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "write README.md: %w" , err )
2020-01-12 15:11:17 +03:00
}
// .gitignore
if len ( opts . Gitignores ) > 0 {
var buf bytes . Buffer
names := strings . Split ( opts . Gitignores , "," )
for _ , name := range names {
2023-03-08 12:31:27 +03:00
data , err = options . Gitignore ( name )
2020-01-12 15:11:17 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "GetRepoInitFile[%s]: %w" , name , err )
2020-01-12 15:11:17 +03:00
}
buf . WriteString ( "# ---> " + name + "\n" )
buf . Write ( data )
buf . WriteString ( "\n" )
}
if buf . Len ( ) > 0 {
2022-01-20 20:46:10 +03:00
if err = os . WriteFile ( filepath . Join ( tmpDir , ".gitignore" ) , buf . Bytes ( ) , 0 o644 ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "write .gitignore: %w" , err )
2020-01-12 15:11:17 +03:00
}
}
}
// LICENSE
if len ( opts . License ) > 0 {
2023-05-05 16:46:17 +03:00
data , err = getLicense ( opts . License , & licenseValues {
Owner : repo . OwnerName ,
Email : authorSig . Email ,
Repo : repo . Name ,
Year : time . Now ( ) . Format ( "2006" ) ,
} )
2020-01-12 15:11:17 +03:00
if err != nil {
2023-05-05 16:46:17 +03:00
return fmt . Errorf ( "getLicense[%s]: %w" , opts . License , err )
2020-01-12 15:11:17 +03:00
}
2022-01-20 20:46:10 +03:00
if err = os . WriteFile ( filepath . Join ( tmpDir , "LICENSE" ) , data , 0 o644 ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "write LICENSE: %w" , err )
2020-01-12 15:11:17 +03:00
}
}
return nil
}
// initRepoCommit temporarily changes with work directory.
2022-01-20 02:26:57 +03:00
func initRepoCommit ( ctx context . Context , tmpPath string , repo * repo_model . Repository , u * user_model . User , defaultBranch string ) ( err error ) {
2020-01-12 15:11:17 +03:00
commitTimeStr := time . Now ( ) . Format ( time . RFC3339 )
sig := u . NewGitSig ( )
// Because this may call hooks we should pass in the environment
env := append ( os . Environ ( ) ,
"GIT_AUTHOR_NAME=" + sig . Name ,
"GIT_AUTHOR_EMAIL=" + sig . Email ,
"GIT_AUTHOR_DATE=" + commitTimeStr ,
"GIT_COMMITTER_DATE=" + commitTimeStr ,
)
2020-09-19 19:44:55 +03:00
committerName := sig . Name
committerEmail := sig . Email
2020-01-12 15:11:17 +03:00
2022-04-01 05:55:30 +03:00
if stdout , _ , err := git . NewCommand ( ctx , "add" , "--all" ) .
2020-01-12 15:11:17 +03:00
SetDescription ( fmt . Sprintf ( "initRepoCommit (git add): %s" , tmpPath ) ) .
2022-04-01 05:55:30 +03:00
RunStdString ( & git . RunOpts { Dir : tmpPath } ) ; err != nil {
2020-01-12 15:11:17 +03:00
log . Error ( "git add --all failed: Stdout: %s\nError: %v" , stdout , err )
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "git add --all: %w" , err )
2020-01-12 15:11:17 +03:00
}
Use `--message=%s` for git commit message (#23028)
Close #23027
`git commit` message option _only_ supports 4 formats (well, only ....):
* `"commit", "-m", msg`
* `"commit", "-m{msg}"` (no space)
* `"commit", "--message", msg`
* `"commit", "--message={msg}"`
The long format with `=` is the best choice, and it's documented in `man
git-commit`:
`-m <msg>, --message=<msg> ...`
ps: I would suggest always use long format option for git command, as
much as possible.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-02-21 09:12:57 +03:00
cmd := git . NewCommand ( ctx , "commit" , "--message=Initial commit" ) .
AddOptionFormat ( "--author='%s <%s>'" , sig . Name , sig . Email )
2020-01-12 15:11:17 +03:00
2022-06-16 18:47:44 +03:00
sign , keyID , signer , _ := asymkey_service . SignInitialCommit ( ctx , tmpPath , u )
if sign {
Refactor git command package to improve security and maintainability (#22678)
This PR follows #21535 (and replace #22592)
## Review without space diff
https://github.com/go-gitea/gitea/pull/22678/files?diff=split&w=1
## Purpose of this PR
1. Make git module command completely safe (risky user inputs won't be
passed as argument option anymore)
2. Avoid low-level mistakes like
https://github.com/go-gitea/gitea/pull/22098#discussion_r1045234918
3. Remove deprecated and dirty `CmdArgCheck` function, hide the `CmdArg`
type
4. Simplify code when using git command
## The main idea of this PR
* Move the `git.CmdArg` to the `internal` package, then no other package
except `git` could use it. Then developers could never do
`AddArguments(git.CmdArg(userInput))` any more.
* Introduce `git.ToTrustedCmdArgs`, it's for user-provided and already
trusted arguments. It's only used in a few cases, for example: use git
arguments from config file, help unit test with some arguments.
* Introduce `AddOptionValues` and `AddOptionFormat`, they make code more
clear and simple:
* Before: `AddArguments("-m").AddDynamicArguments(message)`
* After: `AddOptionValues("-m", message)`
* -
* Before: `AddArguments(git.CmdArg(fmt.Sprintf("--author='%s <%s>'",
sig.Name, sig.Email)))`
* After: `AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email)`
## FAQ
### Why these changes were not done in #21535 ?
#21535 is mainly a search&replace, it did its best to not change too
much logic.
Making the framework better needs a lot of changes, so this separate PR
is needed as the second step.
### The naming of `AddOptionXxx`
According to git's manual, the `--xxx` part is called `option`.
### How can it guarantee that `internal.CmdArg` won't be not misused?
Go's specification guarantees that. Trying to access other package's
internal package causes compilation error.
And, `golangci-lint` also denies the git/internal package. Only the
`git/command.go` can use it carefully.
### There is still a `ToTrustedCmdArgs`, will it still allow developers
to make mistakes and pass untrusted arguments?
Generally speaking, no. Because when using `ToTrustedCmdArgs`, the code
will be very complex (see the changes for examples). Then developers and
reviewers can know that something might be unreasonable.
### Why there was a `CmdArgCheck` and why it's removed?
At the moment of #21535, to reduce unnecessary changes, `CmdArgCheck`
was introduced as a hacky patch. Now, almost all code could be written
as `cmd := NewCommand(); cmd.AddXxx(...)`, then there is no need for
`CmdArgCheck` anymore.
### Why many codes for `signArg == ""` is deleted?
Because in the old code, `signArg` could never be empty string, it's
either `-S[key-id]` or `--no-gpg-sign`. So the `signArg == ""` is just
dead code.
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-02-04 05:30:43 +03:00
cmd . AddOptionFormat ( "-S%s" , keyID )
2022-06-16 18:47:44 +03:00
if repo . GetTrustModel ( ) == repo_model . CommitterTrustModel || repo . GetTrustModel ( ) == repo_model . CollaboratorCommitterTrustModel {
// need to set the committer to the KeyID owner
committerName = signer . Name
committerEmail = signer . Email
2020-01-12 15:11:17 +03:00
}
2022-06-16 18:47:44 +03:00
} else {
2022-10-23 17:44:45 +03:00
cmd . AddArguments ( "--no-gpg-sign" )
2020-01-12 15:11:17 +03:00
}
2020-09-19 19:44:55 +03:00
env = append ( env ,
"GIT_COMMITTER_NAME=" + committerName ,
"GIT_COMMITTER_EMAIL=" + committerEmail ,
)
2022-10-23 17:44:45 +03:00
if stdout , _ , err := cmd .
2020-01-12 15:11:17 +03:00
SetDescription ( fmt . Sprintf ( "initRepoCommit (git commit): %s" , tmpPath ) ) .
2022-04-01 05:55:30 +03:00
RunStdString ( & git . RunOpts { Dir : tmpPath , Env : env } ) ; err != nil {
2022-10-23 17:44:45 +03:00
log . Error ( "Failed to commit: %v: Stdout: %s\nError: %v" , cmd . String ( ) , stdout , err )
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "git commit: %w" , err )
2020-01-12 15:11:17 +03:00
}
2020-03-26 22:14:51 +03:00
if len ( defaultBranch ) == 0 {
2020-06-17 23:53:55 +03:00
defaultBranch = setting . Repository . DefaultBranch
2020-03-26 22:14:51 +03:00
}
2022-10-23 17:44:45 +03:00
if stdout , _ , err := git . NewCommand ( ctx , "push" , "origin" ) . AddDynamicArguments ( "HEAD:" + defaultBranch ) .
2020-01-12 15:11:17 +03:00
SetDescription ( fmt . Sprintf ( "initRepoCommit (git push): %s" , tmpPath ) ) .
2022-05-08 19:46:32 +03:00
RunStdString ( & git . RunOpts { Dir : tmpPath , Env : InternalPushingEnvironment ( u , repo ) } ) ; err != nil {
2020-11-29 00:00:38 +03:00
log . Error ( "Failed to push back to HEAD: Stdout: %s\nError: %v" , stdout , err )
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "git push: %w" , err )
2020-01-12 15:11:17 +03:00
}
return nil
}
2022-01-20 02:26:57 +03:00
func checkInitRepository ( ctx context . Context , owner , name string ) ( err error ) {
2020-01-12 15:11:17 +03:00
// Somehow the directory could exist.
2021-12-10 04:27:50 +03:00
repoPath := repo_model . RepoPath ( owner , 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 {
2021-12-12 18:48:20 +03:00
return repo_model . ErrRepoFilesAlreadyExist {
2020-09-25 07:09:23 +03:00
Uname : owner ,
Name : name ,
}
2020-01-12 15:11:17 +03:00
}
// Init git bare new repository.
2022-01-20 02:26:57 +03:00
if err = git . InitRepository ( ctx , repoPath , true ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "git.InitRepository: %w" , err )
2020-01-20 23:01:19 +03:00
} else if err = createDelegateHooks ( repoPath ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "createDelegateHooks: %w" , err )
2020-01-12 15:11:17 +03:00
}
return nil
}
// InitRepository initializes README and .gitignore if needed.
2022-08-25 05:31:57 +03:00
func initRepository ( ctx context . Context , repoPath string , u * user_model . User , repo * repo_model . Repository , opts CreateRepoOptions ) ( err error ) {
2022-01-20 02:26:57 +03:00
if err = checkInitRepository ( ctx , repo . OwnerName , repo . Name ) ; err != nil {
2020-01-12 15:11:17 +03:00
return err
}
// Initialize repository according to user's choice.
if opts . AutoInit {
2021-09-22 08:38:34 +03:00
tmpDir , err := os . MkdirTemp ( os . TempDir ( ) , "gitea-" + repo . Name )
2020-01-12 15:11:17 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "Failed to create temp dir for repository %s: %w" , repo . RepoPath ( ) , err )
2020-01-12 15:11:17 +03:00
}
2020-08-11 23:05:34 +03:00
defer func ( ) {
if err := util . RemoveAll ( tmpDir ) ; err != nil {
log . Warn ( "Unable to remove temporary directory: %s: Error: %v" , tmpDir , err )
}
} ( )
2020-01-12 15:11:17 +03:00
if err = prepareRepoCommit ( ctx , repo , tmpDir , repoPath , opts ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "prepareRepoCommit: %w" , err )
2020-01-12 15:11:17 +03:00
}
// Apply changes and commit.
2022-01-20 02:26:57 +03:00
if err = initRepoCommit ( ctx , tmpDir , repo , u , opts . DefaultBranch ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "initRepoCommit: %w" , err )
2020-01-12 15:11:17 +03:00
}
}
// Re-fetch the repository from database before updating it (else it would
// override changes that were done earlier with sql)
2022-12-03 05:48:26 +03:00
if repo , err = repo_model . GetRepositoryByID ( ctx , repo . ID ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "getRepositoryByID: %w" , err )
2020-01-12 15:11:17 +03:00
}
if ! opts . AutoInit {
repo . IsEmpty = true
}
2020-09-25 07:09:23 +03:00
repo . DefaultBranch = setting . Repository . DefaultBranch
2020-03-26 22:14:51 +03:00
if len ( opts . DefaultBranch ) > 0 {
repo . DefaultBranch = opts . DefaultBranch
2022-03-29 22:13:41 +03:00
gitRepo , err := git . OpenRepository ( ctx , repo . RepoPath ( ) )
2020-07-05 18:25:46 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "openRepository: %w" , err )
2020-07-05 18:25:46 +03:00
}
2020-12-12 00:41:59 +03:00
defer gitRepo . Close ( )
2020-07-05 18:25:46 +03:00
if err = gitRepo . SetDefaultBranch ( repo . DefaultBranch ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "setDefaultBranch: %w" , err )
2020-07-05 18:25:46 +03:00
}
2023-06-29 13:03:20 +03:00
if ! repo . IsEmpty {
if _ , err := SyncRepoBranches ( ctx , repo . ID , u . ID ) ; err != nil {
return fmt . Errorf ( "SyncRepoBranches: %w" , err )
}
}
2020-03-26 22:14:51 +03:00
}
2022-06-06 11:01:49 +03:00
if err = UpdateRepository ( ctx , repo , false ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "updateRepository: %w" , err )
2020-01-12 15:11:17 +03:00
}
return nil
}
2022-03-29 10:23:45 +03:00
// InitializeLabels adds a label set to a repository using a template
func InitializeLabels ( ctx context . Context , id int64 , labelTemplate string , isOrg bool ) error {
2023-04-10 11:44:02 +03:00
list , err := LoadTemplateLabelsByDisplayName ( labelTemplate )
2022-03-29 10:23:45 +03:00
if err != nil {
return err
}
2022-06-13 12:37:59 +03:00
labels := make ( [ ] * issues_model . Label , len ( list ) )
2022-03-29 10:23:45 +03:00
for i := 0 ; i < len ( list ) ; i ++ {
2022-06-13 12:37:59 +03:00
labels [ i ] = & issues_model . Label {
2023-03-02 02:44:23 +03:00
Name : list [ i ] . Name ,
Exclusive : list [ i ] . Exclusive ,
Description : list [ i ] . Description ,
Color : list [ i ] . Color ,
2022-03-29 10:23:45 +03:00
}
if isOrg {
labels [ i ] . OrgID = id
} else {
labels [ i ] . RepoID = id
}
}
for _ , label := range labels {
2022-06-13 12:37:59 +03:00
if err = issues_model . NewLabel ( ctx , label ) ; err != nil {
2022-03-29 10:23:45 +03:00
return err
}
}
return nil
}
2023-04-10 11:44:02 +03:00
// LoadTemplateLabelsByDisplayName loads a label template by its display name
func LoadTemplateLabelsByDisplayName ( displayName string ) ( [ ] * label . Label , error ) {
if fileName , ok := labelTemplateFileMap [ displayName ] ; ok {
return label . LoadTemplateFile ( fileName )
}
return nil , label . ErrTemplateLoad { TemplateFile : displayName , OriginalError : fmt . Errorf ( "label template %q not found" , displayName ) }
}