aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2023-04-19 21:40:42 +0800
committerGitHub <noreply@github.com>2023-04-19 21:40:42 +0800
commite422342eebc18034ef586ec58f1e2fff0340091d (patch)
tree307264b46c1683915429083d54e9634ee4f2fc4d
parent01214c8ada993bf5f54a4149979d140443d69410 (diff)
downloadgitea-e422342eebc18034ef586ec58f1e2fff0340091d.tar.gz
gitea-e422342eebc18034ef586ec58f1e2fff0340091d.zip
Allow adding new files to an empty repo (#24164)
![image](https://user-images.githubusercontent.com/2114189/232561612-2bfcfd0a-fc04-47ba-965f-5d0bcea46c54.png)
-rw-r--r--models/db/iterate_test.go11
-rw-r--r--models/db/list_test.go11
-rw-r--r--models/dbfs/dbfs_test.go2
-rw-r--r--models/fixtures/repo_unit.yml6
-rw-r--r--models/fixtures/repository.yml1
-rw-r--r--models/fixtures/user.yml2
-rw-r--r--models/repo/repo.go8
-rw-r--r--models/unittest/fixtures.go20
-rw-r--r--models/user/user_test.go8
-rw-r--r--modules/context/context.go2
-rw-r--r--modules/context/repo.go37
-rw-r--r--modules/git/command.go16
-rw-r--r--modules/git/repo.go2
-rw-r--r--modules/git/repo_base_nogogit.go2
-rw-r--r--modules/indexer/code/indexer.go4
-rw-r--r--modules/indexer/stats/db.go7
-rw-r--r--modules/indexer/stats/queue.go5
-rw-r--r--modules/setting/setting.go15
-rw-r--r--routers/init.go2
-rw-r--r--routers/web/repo/editor.go44
-rw-r--r--routers/web/repo/view.go42
-rw-r--r--routers/web/web.go2
-rw-r--r--services/auth/source/db/authenticate.go2
-rw-r--r--services/repository/files/upload.go19
-rw-r--r--templates/repo/editor/commit_form.tmpl2
-rw-r--r--templates/repo/empty.tmpl17
-rw-r--r--templates/repo/home.tmpl28
-rw-r--r--tests/integration/empty_repo_test.go80
-rw-r--r--tests/integration/integration_test.go13
-rw-r--r--tests/test_utils.go37
-rw-r--r--web_src/css/repository.css5
31 files changed, 314 insertions, 138 deletions
diff --git a/models/db/iterate_test.go b/models/db/iterate_test.go
index f9f1213721..5362f34075 100644
--- a/models/db/iterate_test.go
+++ b/models/db/iterate_test.go
@@ -19,13 +19,16 @@ func TestIterate(t *testing.T) {
xe := unittest.GetXORMEngine()
assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
- var repoCnt int
- err := db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error {
- repoCnt++
+ cnt, err := db.GetEngine(db.DefaultContext).Count(&repo_model.RepoUnit{})
+ assert.NoError(t, err)
+
+ var repoUnitCnt int
+ err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error {
+ repoUnitCnt++
return nil
})
assert.NoError(t, err)
- assert.EqualValues(t, 89, repoCnt)
+ assert.EqualValues(t, cnt, repoUnitCnt)
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
diff --git a/models/db/list_test.go b/models/db/list_test.go
index 195450b1e7..6b9bebd64b 100644
--- a/models/db/list_test.go
+++ b/models/db/list_test.go
@@ -31,15 +31,20 @@ func TestFind(t *testing.T) {
xe := unittest.GetXORMEngine()
assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
+ var repoUnitCount int
+ _, err := db.GetEngine(db.DefaultContext).SQL("SELECT COUNT(*) FROM repo_unit").Get(&repoUnitCount)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repoUnitCount)
+
opts := mockListOptions{}
var repoUnits []repo_model.RepoUnit
- err := db.Find(db.DefaultContext, &opts, &repoUnits)
+ err = db.Find(db.DefaultContext, &opts, &repoUnits)
assert.NoError(t, err)
- assert.EqualValues(t, 89, len(repoUnits))
+ assert.EqualValues(t, repoUnitCount, len(repoUnits))
cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
assert.NoError(t, err)
- assert.EqualValues(t, 89, cnt)
+ assert.EqualValues(t, repoUnitCount, cnt)
repoUnits = make([]repo_model.RepoUnit, 0, 10)
newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
diff --git a/models/dbfs/dbfs_test.go b/models/dbfs/dbfs_test.go
index 30aa6463c5..300758c623 100644
--- a/models/dbfs/dbfs_test.go
+++ b/models/dbfs/dbfs_test.go
@@ -12,8 +12,6 @@ import (
"code.gitea.io/gitea/models/db"
"github.com/stretchr/testify/assert"
-
- _ "github.com/mattn/go-sqlite3"
)
func changeDefaultFileBlockSize(n int64) (restore func()) {
diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml
index 184be2d861..5bb974a7d7 100644
--- a/models/fixtures/repo_unit.yml
+++ b/models/fixtures/repo_unit.yml
@@ -601,3 +601,9 @@
repo_id: 57
type: 5
created_unix: 946684810
+
+-
+ id: 90
+ repo_id: 52
+ type: 1
+ created_unix: 946684810
diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml
index 496d1a3e7a..ef7730780f 100644
--- a/models/fixtures/repository.yml
+++ b/models/fixtures/repository.yml
@@ -1560,6 +1560,7 @@
owner_name: user30
lower_name: empty
name: empty
+ default_branch: master
num_watches: 0
num_stars: 0
num_forks: 0
diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml
index fce4a4bda0..eba33a7c36 100644
--- a/models/fixtures/user.yml
+++ b/models/fixtures/user.yml
@@ -1091,7 +1091,7 @@
max_repo_creation: -1
is_active: true
is_admin: false
- is_restricted: true
+ is_restricted: false
allow_git_hook: false
allow_import_local: false
allow_create_organization: true
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 3653dae015..266cbc288c 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -225,6 +225,12 @@ func (repo *Repository) IsBroken() bool {
return repo.Status == RepositoryBroken
}
+// MarkAsBrokenEmpty marks the repo as broken and empty
+func (repo *Repository) MarkAsBrokenEmpty() {
+ repo.Status = RepositoryBroken
+ repo.IsEmpty = true
+}
+
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (repo *Repository) AfterLoad() {
repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
@@ -729,7 +735,7 @@ func IsRepositoryExist(ctx context.Context, u *user_model.User, repoName string)
return false, err
}
isDir, err := util.IsDir(RepoPath(u.Name, repoName))
- return has && isDir, err
+ return has || isDir, err
}
// GetTemplateRepo populates repo.TemplateRepo for a generated repository and
diff --git a/models/unittest/fixtures.go b/models/unittest/fixtures.go
index 545452a159..f7ee766731 100644
--- a/models/unittest/fixtures.go
+++ b/models/unittest/fixtures.go
@@ -17,7 +17,7 @@ import (
"xorm.io/xorm/schemas"
)
-var fixtures *testfixtures.Loader
+var fixturesLoader *testfixtures.Loader
// GetXORMEngine gets the XORM engine
func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
@@ -30,11 +30,11 @@ func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
// InitFixtures initialize test fixtures for a test database
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
e := GetXORMEngine(engine...)
- var testfiles func(*testfixtures.Loader) error
+ var fixtureOptionFiles func(*testfixtures.Loader) error
if opts.Dir != "" {
- testfiles = testfixtures.Directory(opts.Dir)
+ fixtureOptionFiles = testfixtures.Directory(opts.Dir)
} else {
- testfiles = testfixtures.Files(opts.Files...)
+ fixtureOptionFiles = testfixtures.Files(opts.Files...)
}
dialect := "unknown"
switch e.Dialect().URI().DBType {
@@ -54,14 +54,14 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
testfixtures.Database(e.DB().DB),
testfixtures.Dialect(dialect),
testfixtures.DangerousSkipTestDatabaseCheck(),
- testfiles,
+ fixtureOptionFiles,
}
if e.Dialect().URI().DBType == schemas.POSTGRES {
loaderOptions = append(loaderOptions, testfixtures.SkipResetSequences())
}
- fixtures, err = testfixtures.New(loaderOptions...)
+ fixturesLoader, err = testfixtures.New(loaderOptions...)
if err != nil {
return err
}
@@ -78,11 +78,9 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
func LoadFixtures(engine ...*xorm.Engine) error {
e := GetXORMEngine(engine...)
var err error
- // Database transaction conflicts could occur and result in ROLLBACK
- // As a simple workaround, we just retry 20 times.
- for i := 0; i < 20; i++ {
- err = fixtures.Load()
- if err == nil {
+ // (doubt) database transaction conflicts could occur and result in ROLLBACK? just try for a few times.
+ for i := 0; i < 5; i++ {
+ if err = fixturesLoader.Load(); err == nil {
break
}
time.Sleep(200 * time.Millisecond)
diff --git a/models/user/user_test.go b/models/user/user_test.go
index 8e78fee6b3..c2314d5c03 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -5,6 +5,7 @@ package user_test
import (
"context"
+ "fmt"
"math/rand"
"strings"
"testing"
@@ -64,9 +65,10 @@ func TestSearchUsers(t *testing.T) {
testSuccess := func(opts *user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
users, _, err := user_model.SearchUsers(opts)
assert.NoError(t, err)
- if assert.Len(t, users, len(expectedUserOrOrgIDs), opts) {
+ cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts)
+ if assert.Len(t, users, len(expectedUserOrOrgIDs), "case: %s", cassText) {
for i, expectedID := range expectedUserOrOrgIDs {
- assert.EqualValues(t, expectedID, users[i].ID)
+ assert.EqualValues(t, expectedID, users[i].ID, "case: %s", cassText)
}
}
}
@@ -118,7 +120,7 @@ func TestSearchUsers(t *testing.T) {
[]int64{1})
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue},
- []int64{29, 30})
+ []int64{29})
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
[]int64{30})
diff --git a/modules/context/context.go b/modules/context/context.go
index 2507cc10c0..21bae91129 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -301,7 +301,7 @@ func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
// it's safe to show internal error to admin users, and it helps
if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
- ctx.Data["ErrorMsg"] = logErr
+ ctx.Data["ErrorMsg"] = fmt.Sprintf("%s, %s", logMsg, logErr)
}
}
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 8b4d0c1bf4..1736de2e4b 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -184,6 +184,9 @@ func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bo
// GetCommitsCount returns cached commit count for current view
func (r *Repository) GetCommitsCount() (int64, error) {
+ if r.Commit == nil {
+ return 0, nil
+ }
var contextName string
if r.IsViewBranch {
contextName = r.BranchName
@@ -642,8 +645,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
if err != nil {
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
- ctx.Repo.Repository.Status = repo_model.RepositoryBroken
- ctx.Repo.Repository.IsEmpty = true
+ ctx.Repo.Repository.MarkAsBrokenEmpty()
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
// Only allow access to base of repo or settings
if !isHomeOrSettings {
@@ -689,7 +691,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Data["BranchesCount"] = len(brs)
// If not branch selected, try default one.
- // If default branch doesn't exists, fall back to some other branch.
+ // If default branch doesn't exist, fall back to some other branch.
if len(ctx.Repo.BranchName) == 0 {
if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
@@ -878,6 +880,10 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
return func(ctx *Context) (cancel context.CancelFunc) {
// Empty repository does not have reference information.
if ctx.Repo.Repository.IsEmpty {
+ // assume the user is viewing the (non-existent) default branch
+ ctx.Repo.IsViewBranch = true
+ ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
+ ctx.Data["TreePath"] = ""
return
}
@@ -907,27 +913,30 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
refName = ctx.Repo.Repository.DefaultBranch
if !ctx.Repo.GitRepo.IsBranchExist(refName) {
brs, _, err := ctx.Repo.GitRepo.GetBranchNames(0, 0)
- if err != nil {
- ctx.ServerError("GetBranches", err)
- return
+ if err == nil && len(brs) != 0 {
+ refName = brs[0]
} else if len(brs) == 0 {
- err = fmt.Errorf("No branches in non-empty repository %s",
- ctx.Repo.GitRepo.Path)
- ctx.ServerError("GetBranches", err)
- return
+ log.Error("No branches in non-empty repository %s", ctx.Repo.GitRepo.Path)
+ ctx.Repo.Repository.MarkAsBrokenEmpty()
+ } else {
+ log.Error("GetBranches error: %v", err)
+ ctx.Repo.Repository.MarkAsBrokenEmpty()
}
- refName = brs[0]
}
ctx.Repo.RefName = refName
ctx.Repo.BranchName = refName
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
- if err != nil {
+ if err == nil {
+ ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+ } else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
+ // if the repository is broken, we can continue to the handler code, to show "Settings -> Delete Repository" for end users
+ log.Error("GetBranchCommit: %v", err)
+ ctx.Repo.Repository.MarkAsBrokenEmpty()
+ } else {
ctx.ServerError("GetBranchCommit", err)
return
}
- ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
ctx.Repo.IsViewBranch = true
-
} else {
refName = getRefName(ctx, refType)
ctx.Repo.RefName = refName
diff --git a/modules/git/command.go b/modules/git/command.go
index a42d859f55..ac013d4ea1 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -211,10 +211,18 @@ type RunOpts struct {
Env []string
Timeout time.Duration
UseContextTimeout bool
- Dir string
- Stdout, Stderr io.Writer
- Stdin io.Reader
- PipelineFunc func(context.Context, context.CancelFunc) error
+
+ // Dir is the working dir for the git command, however:
+ // FIXME: this could be incorrect in many cases, for example:
+ // * /some/path/.git
+ // * /some/path/.git/gitea-data/data/repositories/user/repo.git
+ // If "user/repo.git" is invalid/broken, then running git command in it will use "/some/path/.git", and produce unexpected results
+ // The correct approach is to use `--git-dir" global argument
+ Dir string
+
+ Stdout, Stderr io.Writer
+ Stdin io.Reader
+ PipelineFunc func(context.Context, context.CancelFunc) error
}
func commonBaseEnvs() []string {
diff --git a/modules/git/repo.go b/modules/git/repo.go
index d29ec40ae2..3637aa47c4 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -80,7 +80,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
// IsEmpty Check if repository is empty.
func (repo *Repository) IsEmpty() (bool, error) {
var errbuf, output strings.Builder
- if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$").
+ if err := NewCommand(repo.Ctx).AddOptionFormat("--git-dir=%s", repo.Path).AddArguments("show-ref", "--head", "^HEAD$").
Run(&RunOpts{
Dir: repo.Path,
Stdout: &output,
diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go
index a0216d14a6..e0f2d563b3 100644
--- a/modules/git/repo_base_nogogit.go
+++ b/modules/git/repo_base_nogogit.go
@@ -61,7 +61,7 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
}
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
- repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
+ repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath)
return repo, nil
}
diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go
index 027d13555c..2c493ccf94 100644
--- a/modules/indexer/code/indexer.go
+++ b/modules/indexer/code/indexer.go
@@ -154,7 +154,9 @@ func Init() {
log.Trace("IndexerData Process Repo: %d", indexerData.RepoID)
if err := index(ctx, indexer, indexerData.RepoID); err != nil {
- log.Error("index: %v", err)
+ if !setting.IsInTesting {
+ log.Error("indexer index error for repo %v: %v", indexerData.RepoID, err)
+ }
if indexer.Ping() {
continue
}
diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go
index 9bbdcad60d..2a0475dea6 100644
--- a/modules/indexer/stats/db.go
+++ b/modules/indexer/stats/db.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
+ "code.gitea.io/gitea/modules/setting"
)
// DBIndexer implements Indexer interface to use database's like search
@@ -46,7 +47,7 @@ func (db *DBIndexer) Index(id int64) error {
// Get latest commit for default branch
commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch)
if err != nil {
- if git.IsErrBranchNotExist(err) || git.IsErrNotExist(err) {
+ if git.IsErrBranchNotExist(err) || git.IsErrNotExist(err) || setting.IsInTesting {
log.Debug("Unable to get commit ID for default branch %s in %s ... skipping this repository", repo.DefaultBranch, repo.RepoPath())
return nil
}
@@ -62,7 +63,9 @@ func (db *DBIndexer) Index(id int64) error {
// Calculate and save language statistics to database
stats, err := gitRepo.GetLanguageStats(commitID)
if err != nil {
- log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
+ if !setting.IsInTesting {
+ log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
+ }
return err
}
err = repo_model.UpdateLanguageStats(repo, commitID, stats)
diff --git a/modules/indexer/stats/queue.go b/modules/indexer/stats/queue.go
index 32379f2859..a57338e07d 100644
--- a/modules/indexer/stats/queue.go
+++ b/modules/indexer/stats/queue.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/queue"
+ "code.gitea.io/gitea/modules/setting"
)
// statsQueue represents a queue to handle repository stats updates
@@ -20,7 +21,9 @@ func handle(data ...queue.Data) []queue.Data {
for _, datum := range data {
opts := datum.(int64)
if err := indexer.Index(opts); err != nil {
- log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
+ if !setting.IsInTesting {
+ log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
+ }
}
}
return nil
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 4d7a7caab8..e1a57615a8 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -27,7 +27,7 @@ import (
var (
// AppVer is the version of the current build of Gitea. It is set in main.go from main.Version.
AppVer string
- // AppBuiltWith represents a human readable version go runtime build version and build tags. (See main.go formatBuiltWith().)
+ // AppBuiltWith represents a human-readable version go runtime build version and build tags. (See main.go formatBuiltWith().)
AppBuiltWith string
// AppStartTime store time gitea has started
AppStartTime time.Time
@@ -40,7 +40,8 @@ var (
// AppWorkPath is used as the base path for several other paths.
AppWorkPath string
- // Global setting objects
+ // Other global setting objects
+
CfgProvider ConfigProvider
CustomPath string // Custom directory path
CustomConf string
@@ -48,6 +49,10 @@ var (
RunUser string
IsProd bool
IsWindows bool
+
+ // IsInTesting indicates whether the testing is running. A lot of unreliable code causes a lot of nonsense error logs during testing
+ // TODO: this is only a temporary solution, we should make the test code more reliable
+ IsInTesting = false
)
func getAppPath() (string, error) {
@@ -108,8 +113,12 @@ func getWorkPath(appPath string) string {
func init() {
IsWindows = runtime.GOOS == "windows"
+ if AppVer == "" {
+ AppVer = "dev"
+ }
+
// We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically
- // By default set this logger at Info - we'll change it later but we need to start with something.
+ // By default set this logger at Info - we'll change it later, but we need to start with something.
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "info", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
var err error
diff --git a/routers/init.go b/routers/init.go
index c539975aca..af768abbf4 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -108,6 +108,7 @@ func GlobalInitInstalled(ctx context.Context) {
}
mustInitCtx(ctx, git.InitFull)
+ log.Info("Gitea Version: %s%s", setting.AppVer, setting.AppBuiltWith)
log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir())
log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath)
@@ -115,7 +116,6 @@ func GlobalInitInstalled(ctx context.Context) {
log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf)
log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode))
- log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith)
// Setup i18n
translation.InitLocales(ctx)
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 476c1d5ddd..63387df281 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -82,7 +82,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
}
// Check if the filename (and additional path) is specified in the querystring
- // (filename is a misnomer, but kept for compatibility with Github)
+ // (filename is a misnomer, but kept for compatibility with GitHub)
filePath, fileName := path.Split(ctx.Req.URL.Query().Get("filename"))
filePath = strings.Trim(filePath, "/")
treeNames, treePaths := getParentTreeFields(path.Join(ctx.Repo.TreePath, filePath))
@@ -327,6 +327,10 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
}
}
+ if ctx.Repo.Repository.IsEmpty {
+ _ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
+ }
+
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
@@ -617,25 +621,25 @@ func UploadFilePost(ctx *context.Context) {
return
}
- var newTreePath string
- for _, part := range treeNames {
- newTreePath = path.Join(newTreePath, part)
- entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
- if err != nil {
- if git.IsErrNotExist(err) {
- // Means there is no item with that name, so we're good
- break
+ if !ctx.Repo.Repository.IsEmpty {
+ var newTreePath string
+ for _, part := range treeNames {
+ newTreePath = path.Join(newTreePath, part)
+ entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
+ if err != nil {
+ if git.IsErrNotExist(err) {
+ break // Means there is no item with that name, so we're good
+ }
+ ctx.ServerError("Repo.Commit.GetTreeEntryByPath", err)
+ return
}
- ctx.ServerError("Repo.Commit.GetTreeEntryByPath", err)
- return
- }
-
- // User can only upload files to a directory.
- if !entry.IsDir() {
- ctx.Data["Err_TreePath"] = true
- ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
- return
+ // User can only upload files to a directory, the directory name shouldn't be an existing file.
+ if !entry.IsDir() {
+ ctx.Data["Err_TreePath"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
+ return
+ }
}
}
@@ -714,6 +718,10 @@ func UploadFilePost(ctx *context.Context) {
return
}
+ if ctx.Repo.Repository.IsEmpty {
+ _ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
+ }
+
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
} else {
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 150050f76b..5a11073ba9 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -154,16 +154,6 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
}
- // Check permission to add or upload new file.
- if ctx.Repo.CanWrite(unit_model.TypeCode) && ctx.Repo.IsViewBranch {
- ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived
- ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived
- }
-
- if ctx.Written() {
- return
- }
-
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
if err != nil {
ctx.ServerError("findReadmeFileInEntries", err)
@@ -868,21 +858,25 @@ func renderRepoTopics(ctx *context.Context) {
func renderCode(ctx *context.Context) {
ctx.Data["PageIsViewCode"] = true
+ ctx.Data["RepositoryUploadEnabled"] = setting.Repository.Upload.Enabled
- if ctx.Repo.Repository.IsEmpty {
- reallyEmpty := true
+ if ctx.Repo.Commit == nil || ctx.Repo.Repository.IsEmpty || ctx.Repo.Repository.IsBroken() {
+ showEmpty := true
var err error
if ctx.Repo.GitRepo != nil {
- reallyEmpty, err = ctx.Repo.GitRepo.IsEmpty()
+ showEmpty, err = ctx.Repo.GitRepo.IsEmpty()
if err != nil {
- ctx.ServerError("GitRepo.IsEmpty", err)
- return
+ log.Error("GitRepo.IsEmpty: %v", err)
+ ctx.Repo.Repository.Status = repo_model.RepositoryBroken
+ showEmpty = true
+ ctx.Flash.Error(ctx.Tr("error.occurred"), true)
}
}
- if reallyEmpty {
+ if showEmpty {
ctx.HTML(http.StatusOK, tplRepoEMPTY)
return
}
+
// the repo is not really empty, so we should update the modal in database
// such problem may be caused by:
// 1) an error occurs during pushing/receiving. 2) the user replaces an empty git repo manually
@@ -898,6 +892,14 @@ func renderCode(ctx *context.Context) {
ctx.ServerError("UpdateRepoSize", err)
return
}
+
+ // the repo's IsEmpty has been updated, redirect to this page to make sure middlewares can get the correct values
+ link := ctx.Link
+ if ctx.Req.URL.RawQuery != "" {
+ link += "?" + ctx.Req.URL.RawQuery
+ }
+ ctx.Redirect(link)
+ return
}
title := ctx.Repo.Repository.Owner.Name + "/" + ctx.Repo.Repository.Name
@@ -927,11 +929,9 @@ func renderCode(ctx *context.Context) {
return
}
- if !ctx.Repo.Repository.IsEmpty {
- checkCitationFile(ctx, entry)
- if ctx.Written() {
- return
- }
+ checkCitationFile(ctx, entry)
+ if ctx.Written() {
+ return
}
renderLanguageStats(ctx)
diff --git a/routers/web/web.go b/routers/web/web.go
index a4a1b7113c..30a8314691 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1184,7 +1184,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/upload-file", repo.UploadFileToServer)
m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
}, repo.MustBeEditable, repo.MustBeAbleToUpload)
- }, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived(), repo.MustBeNotEmpty)
+ }, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived())
m.Group("/branches", func() {
m.Group("/_new", func() {
diff --git a/services/auth/source/db/authenticate.go b/services/auth/source/db/authenticate.go
index 76445e0d6d..773ec601ba 100644
--- a/services/auth/source/db/authenticate.go
+++ b/services/auth/source/db/authenticate.go
@@ -32,7 +32,7 @@ func Authenticate(user *user_model.User, login, password string) (*user_model.Us
}
// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
- // user could be hint to resend confirm email.
+ // user could be hinted to resend confirm email.
if user.ProhibitLogin {
return nil, user_model.ErrUserProhibitLogin{
UID: user.ID,
diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go
index cf2f7019b6..338811f0f1 100644
--- a/services/repository/files/upload.go
+++ b/services/repository/files/upload.go
@@ -86,11 +86,22 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
return err
}
defer t.Close()
- if err := t.Clone(opts.OldBranch); err != nil {
- return err
+
+ hasOldBranch := true
+ if err = t.Clone(opts.OldBranch); err != nil {
+ if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
+ return err
+ }
+ if err = t.Init(); err != nil {
+ return err
+ }
+ hasOldBranch = false
+ opts.LastCommitID = ""
}
- if err := t.SetDefaultIndex(); err != nil {
- return err
+ if hasOldBranch {
+ if err = t.SetDefaultIndex(); err != nil {
+ return err
+ }
}
var filename2attribute2info map[string]map[string]string
diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl
index 7ac0ed3df1..db798d92e8 100644
--- a/templates/repo/editor/commit_form.tmpl
+++ b/templates/repo/editor/commit_form.tmpl
@@ -39,6 +39,7 @@
</label>
</div>
</div>
+ {{if not .Repository.IsEmpty}}
<div class="field">
{{$pullRequestEnabled := .Repository.UnitEnabled $.Context $.UnitTypePullRequests}}
{{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}}
@@ -65,6 +66,7 @@
<span class="text-muted js-quick-pull-normalization-info"></span>
</div>
</div>
+ {{end}}
</div>
</div>
<button id="commit-button" type="submit" class="ui green button">
diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl
index cb883e8df5..0acb08933a 100644
--- a/templates/repo/empty.tmpl
+++ b/templates/repo/empty.tmpl
@@ -21,8 +21,21 @@
<div class="ui attached guide table segment empty-repo-guide">
<div class="item">
<h3>{{.locale.Tr "repo.clone_this_repo"}} <small>{{.locale.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2html}}</small></h3>
- <div class="ui action small input">
- {{template "repo/clone_buttons" .}}
+
+ <div class="gt-df">
+ {{if and .CanWriteCode (not .Repository.IsArchived)}}
+ <a class="ui small button" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/">
+ {{.locale.Tr "repo.editor.new_file"}}
+ </a>
+ {{if .RepositoryUploadEnabled}}
+ <a class="ui small button" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/">
+ {{.locale.Tr "repo.editor.upload_file"}}
+ </a>
+ {{end}}
+ {{end}}
+ <div class="ui action small input gt-df gt-f1">
+ {{template "repo/clone_buttons" .}}
+ </div>
</div>
</div>
diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl
index 8de54611c3..4db12f2c95 100644
--- a/templates/repo/home.tmpl
+++ b/templates/repo/home.tmpl
@@ -71,29 +71,27 @@
{{end}}
<a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">{{.locale.Tr "repo.find_file.go_to_file"}}</a>
{{end}}
- {{if or .CanAddFile .CanUploadFile}}
+
+ {{if and .CanWriteCode .IsViewBranch (not .Repository.IsArchived)}}
<button class="ui basic compact dropdown jump icon button gt-mr-2"{{if not .Repository.CanEnableEditor}} disabled{{end}}>
<span class="text">{{.locale.Tr "repo.editor.add_file"}}</span>
<div class="menu">
- {{if .CanAddFile}}
- <a class="item" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
- {{.locale.Tr "repo.editor.new_file"}}
- </a>
- {{end}}
- {{if .CanUploadFile}}
- <a class="item" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
- {{.locale.Tr "repo.editor.upload_file"}}
- </a>
- {{end}}
- {{if .CanAddFile}}
- <a class="item" href="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
- {{.locale.Tr "repo.editor.patch"}}
- </a>
+ <a class="item" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
+ {{.locale.Tr "repo.editor.new_file"}}
+ </a>
+ {{if .RepositoryUploadEnabled}}
+ <a class="item" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
+ {{.locale.Tr "repo.editor.upload_file"}}
+ </a>
{{end}}
+ <a class="item" href="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
+ {{.locale.Tr "repo.editor.patch"}}
+ </a>
</div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</button>
{{end}}
+
{{if and (eq $n 0) (.Repository.IsTemplate)}}
<a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}">
{{.locale.Tr "repo.use_template"}}
diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go
index 1a83de1292..80697c7329 100644
--- a/tests/integration/empty_repo_test.go
+++ b/tests/integration/empty_repo_test.go
@@ -4,12 +4,19 @@
package integration
import (
+ "bytes"
+ "io"
+ "mime/multipart"
"net/http"
"testing"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -17,7 +24,7 @@ import (
func TestEmptyRepo(t *testing.T) {
defer tests.PrepareTestEnv(t)()
- subpaths := []string{
+ subPaths := []string{
"commits/master",
"raw/foo",
"commit/1ae57b34ccf7e18373",
@@ -26,8 +33,75 @@ func TestEmptyRepo(t *testing.T) {
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
assert.True(t, emptyRepo.IsEmpty)
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
- for _, subpath := range subpaths {
- req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath)
+ for _, subPath := range subPaths {
+ req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subPath)
MakeRequest(t, req, http.StatusNotFound)
}
}
+
+func TestEmptyRepoAddFile(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ err := user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 30, ProhibitLogin: false}, "prohibit_login")
+ assert.NoError(t, err)
+
+ session := loginUser(t, "user30")
+ req := NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`)
+ assert.Equal(t, "", doc.AttrOr("checked", "_no_"))
+ req = NewRequestWithValues(t, "POST", "/user30/empty/_new/"+setting.Repository.DefaultBranch, map[string]string{
+ "_csrf": GetCSRF(t, session, "/user/settings"),
+ "commit_choice": "direct",
+ "tree_path": "test-file.md",
+ "content": "newly-added-test-file",
+ })
+
+ resp = session.MakeRequest(t, req, http.StatusSeeOther)
+ redirect := test.RedirectURL(resp)
+ assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch+"/test-file.md", redirect)
+
+ req = NewRequest(t, "GET", redirect)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "newly-added-test-file")
+}
+
+func TestEmptyRepoUploadFile(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ err := user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 30, ProhibitLogin: false}, "prohibit_login")
+ assert.NoError(t, err)
+
+ session := loginUser(t, "user30")
+ req := NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`)
+ assert.Equal(t, "", doc.AttrOr("checked", "_no_"))
+
+ body := &bytes.Buffer{}
+ mpForm := multipart.NewWriter(body)
+ _ = mpForm.WriteField("_csrf", GetCSRF(t, session, "/user/settings"))
+ file, _ := mpForm.CreateFormFile("file", "uploaded-file.txt")
+ _, _ = io.Copy(file, bytes.NewBufferString("newly-uploaded-test-file"))
+ _ = mpForm.Close()
+
+ req = NewRequestWithBody(t, "POST", "/user30/empty/upload-file", body)
+ req.Header.Add("Content-Type", mpForm.FormDataContentType())
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ respMap := map[string]string{}
+ assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), &respMap))
+
+ req = NewRequestWithValues(t, "POST", "/user30/empty/_upload/"+setting.Repository.DefaultBranch, map[string]string{
+ "_csrf": GetCSRF(t, session, "/user/settings"),
+ "commit_choice": "direct",
+ "files": respMap["uuid"],
+ "tree_path": "",
+ })
+ resp = session.MakeRequest(t, req, http.StatusSeeOther)
+ redirect := test.RedirectURL(resp)
+ assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch+"/", redirect)
+
+ req = NewRequest(t, "GET", redirect)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "uploaded-file.txt")
+}
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index 965bae576c..33a815b154 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -124,6 +124,9 @@ func TestMain(m *testing.M) {
fmt.Printf("Error initializing test database: %v\n", err)
os.Exit(1)
}
+
+ // FIXME: the console logger is deleted by mistake, so if there is any `log.Fatal`, developers won't see any error message.
+ // Instead, "No tests were found", last nonsense log is "According to the configuration, subsequent logs will not be printed to the console"
exitCode := m.Run()
tests.WriterCloser.Reset()
@@ -366,10 +369,12 @@ const NoExpectedStatus = -1
func MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.ResponseRecorder {
t.Helper()
recorder := httptest.NewRecorder()
+ if req.RemoteAddr == "" {
+ req.RemoteAddr = "test-mock:12345"
+ }
c.ServeHTTP(recorder, req)
if expectedStatus != NoExpectedStatus {
- if !assert.EqualValues(t, expectedStatus, recorder.Code,
- "Request: %s %s", req.Method, req.URL.String()) {
+ if !assert.EqualValues(t, expectedStatus, recorder.Code, "Request: %s %s", req.Method, req.URL.String()) {
logUnexpectedResponse(t, recorder)
}
}
@@ -410,8 +415,10 @@ func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
return
} else if len(respBytes) < 500 {
// if body is short, just log the whole thing
- t.Log("Response:", string(respBytes))
+ t.Log("Response: ", string(respBytes))
return
+ } else {
+ t.Log("Response length: ", len(respBytes))
}
// log the "flash" error message, if one exists
diff --git a/tests/test_utils.go b/tests/test_utils.go
index 102dd3d298..b3c98427c3 100644
--- a/tests/test_utils.go
+++ b/tests/test_utils.go
@@ -10,7 +10,6 @@ import (
"os"
"path"
"path/filepath"
- "runtime"
"testing"
"code.gitea.io/gitea/models/db"
@@ -30,29 +29,44 @@ import (
"github.com/stretchr/testify/assert"
)
+func exitf(format string, args ...interface{}) {
+ fmt.Printf(format+"\n", args...)
+ os.Exit(1)
+}
+
func InitTest(requireGitea bool) {
giteaRoot := base.SetupGiteaRoot()
if giteaRoot == "" {
- fmt.Println("Environment variable $GITEA_ROOT not set")
- os.Exit(1)
+ exitf("Environment variable $GITEA_ROOT not set")
}
+ setting.AppWorkPath = giteaRoot
if requireGitea {
giteaBinary := "gitea"
- if runtime.GOOS == "windows" {
+ if setting.IsWindows {
giteaBinary += ".exe"
}
setting.AppPath = path.Join(giteaRoot, giteaBinary)
if _, err := os.Stat(setting.AppPath); err != nil {
- fmt.Printf("Could not find gitea binary at %s\n", setting.AppPath)
- os.Exit(1)
+ exitf("Could not find gitea binary at %s", setting.AppPath)
}
}
giteaConf := os.Getenv("GITEA_CONF")
if giteaConf == "" {
- fmt.Println("Environment variable $GITEA_CONF not set")
- os.Exit(1)
- } else if !path.IsAbs(giteaConf) {
+ // By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
+ // It's easier for developers to debug bugs step by step with a debugger.
+ // Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
+ giteaConf = "tests/sqlite.ini"
+ _ = os.Setenv("GITEA_CONF", giteaConf)
+ fmt.Printf("Environment variable $GITEA_CONF not set, use default: %s\n", giteaConf)
+ if !setting.EnableSQLite3 {
+ exitf(`Need to enable SQLite3 for sqlite.ini testing, please set: -tags "sqlite,sqlite_unlock_notify"`)
+ }
+ }
+
+ setting.IsInTesting = true
+
+ if !path.IsAbs(giteaConf) {
setting.CustomConf = path.Join(giteaRoot, giteaConf)
} else {
setting.CustomConf = giteaConf
@@ -69,8 +83,7 @@ func InitTest(requireGitea bool) {
setting.LoadDBSetting()
if err := storage.Init(); err != nil {
- fmt.Printf("Init storage failed: %v", err)
- os.Exit(1)
+ exitf("Init storage failed: %v", err)
}
switch {
@@ -221,7 +234,7 @@ func PrepareTestEnv(t testing.TB, skip ...int) func() {
return deferFn
}
-// resetFixtures flushes queues, reloads fixtures and resets test repositories within a single test.
+// ResetFixtures flushes queues, reloads fixtures and resets test repositories within a single test.
// Most tests should call defer tests.PrepareTestEnv(t)() (or have onGiteaRun do that for them) but sometimes
// within a single test this is required
func ResetFixtures(t *testing.T) {
diff --git a/web_src/css/repository.css b/web_src/css/repository.css
index 05e50548d9..8e764f54cd 100644
--- a/web_src/css/repository.css
+++ b/web_src/css/repository.css
@@ -1911,15 +1911,12 @@
border-radius: var(--border-radius) 0 0 var(--border-radius);
}
-.repository.quickstart .guide .ui.action.small.input {
- width: 100%;
-}
-
.repository.quickstart .guide #repo-clone-url {
border-radius: 0;
padding: 5px 10px;
font-size: 1.2em;
line-height: 1.4;
+ flex: 1
}
.repository.release #release-list {