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 @@ + {{if not .Repository.IsEmpty}}