Skip to content

Commit 1dbc58f

Browse files
More pleasantly handle broken or missing git repositories (#17747)
* More pleasantly handle broken or missing git repositories In #17742 it was noted that there a completely invalid git repository underlying a repo on gitea.com. This happened due to a problem during a migration however, it is not beyond the realms of possibility that a corruption could occur to another user. This PR adds a check to RepoAssignment that will detect if a repository loading has failed due to an absent git repository. It will then show a page suggesting the user contacts the administrator or deletes the repository. Fix #17742 Signed-off-by: Andrew Thornton <[email protected]> * Update options/locale/locale_en-US.ini Co-authored-by: techknowlogick <[email protected]> Co-authored-by: techknowlogick <[email protected]>
1 parent baed01f commit 1dbc58f

File tree

6 files changed

+63
-4
lines changed

6 files changed

+63
-4
lines changed

models/repo.go

+6
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ const (
146146
RepositoryReady RepositoryStatus = iota // a normal repository
147147
RepositoryBeingMigrated // repository is migrating
148148
RepositoryPendingTransfer // repository pending in ownership transfer state
149+
RepositoryBroken // repository is in a permanently broken state
149150
)
150151

151152
// TrustModelType defines the types of trust model for this repository
@@ -289,6 +290,11 @@ func (repo *Repository) IsBeingCreated() bool {
289290
return repo.IsBeingMigrated()
290291
}
291292

293+
// IsBroken indicates that repository is broken
294+
func (repo *Repository) IsBroken() bool {
295+
return repo.Status == RepositoryBroken
296+
}
297+
292298
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
293299
func (repo *Repository) AfterLoad() {
294300
// FIXME: use models migration to solve all at once.

modules/context/repo.go

+33-1
Original file line numberDiff line numberDiff line change
@@ -522,14 +522,30 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
522522
}
523523
}
524524

525+
isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/")
526+
525527
// Disable everything when the repo is being created
526-
if ctx.Repo.Repository.IsBeingCreated() {
528+
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
527529
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
530+
if !isHomeOrSettings {
531+
ctx.Redirect(ctx.Repo.RepoLink)
532+
}
528533
return
529534
}
530535

531536
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
532537
if err != nil {
538+
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
539+
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
540+
ctx.Repo.Repository.Status = models.RepositoryBroken
541+
ctx.Repo.Repository.IsEmpty = true
542+
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
543+
// Only allow access to base of repo or settings
544+
if !isHomeOrSettings {
545+
ctx.Redirect(ctx.Repo.RepoLink)
546+
}
547+
return
548+
}
533549
ctx.ServerError("RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
534550
return
535551
}
@@ -551,6 +567,17 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
551567

552568
tags, err := ctx.Repo.GitRepo.GetTags(0, 0)
553569
if err != nil {
570+
if strings.Contains(err.Error(), "fatal: not a git repository ") {
571+
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
572+
ctx.Repo.Repository.Status = models.RepositoryBroken
573+
ctx.Repo.Repository.IsEmpty = true
574+
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
575+
// Only allow access to base of repo or settings
576+
if !isHomeOrSettings {
577+
ctx.Redirect(ctx.Repo.RepoLink)
578+
}
579+
return
580+
}
554581
ctx.ServerError("GetTags", err)
555582
return
556583
}
@@ -919,6 +946,11 @@ func UnitTypes() func(ctx *Context) {
919946
// IssueTemplatesFromDefaultBranch checks for issue templates in the repo's default branch
920947
func (ctx *Context) IssueTemplatesFromDefaultBranch() []api.IssueTemplate {
921948
var issueTemplates []api.IssueTemplate
949+
950+
if ctx.Repo.Repository.IsEmpty {
951+
return issueTemplates
952+
}
953+
922954
if ctx.Repo.Commit == nil {
923955
var err error
924956
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)

options/locale/locale_en-US.ini

+1
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ clone_this_repo = Clone this repository
946946
create_new_repo_command = Creating a new repository on the command line
947947
push_exist_repo = Pushing an existing repository from the command line
948948
empty_message = This repository does not contain any content.
949+
broken_message = The git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
949950

950951
code = Code
951952
code.desc = Access source code, files, commits and branches.

routers/private/serv.go

+8
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ func ServCommand(ctx *context.PrivateContext) {
162162
return
163163
}
164164

165+
if repo.IsBroken() {
166+
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
167+
Results: results,
168+
Err: "Repository is in a broken state",
169+
})
170+
return
171+
}
172+
165173
// We can shortcut at this point if the repo is a mirror
166174
if mode > models.AccessModeRead && repo.IsMirror {
167175
ctx.JSON(http.StatusForbidden, private.ErrServCommand{

templates/repo/empty.tmpl

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
{{.i18n.Tr "repo.archive.title"}}
1111
</div>
1212
{{end}}
13-
{{if .CanWriteCode}}
13+
{{if .Repository.IsBroken}}
14+
<div class="ui segment center">
15+
{{.i18n.Tr "repo.broken_message"}}
16+
</div>
17+
{{else if .CanWriteCode}}
1418
<h4 class="ui top attached header">
1519
{{.i18n.Tr "repo.quick_guide"}}
1620
</h4>

templates/repo/header.tmpl

+10-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{.BaseRepo.FullName}}</a></div>{{end}}
4141
{{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{.TemplateRepo.FullName}}</a></div>{{end}}
4242
</div>
43-
{{if not .IsBeingCreated}}
43+
{{if not (or .IsBeingCreated .IsBroken)}}
4444
<div class="repo-buttons">
4545
{{if $.RepoTransfer}}
4646
<form method="post" action="{{$.RepoLink}}/action/accept_transfer?redirect_to={{$.RepoLink}}">
@@ -100,7 +100,7 @@
100100
</div><!-- end container -->
101101
{{end}}
102102
<div class="ui tabs container">
103-
{{if not .Repository.IsBeingCreated}}
103+
{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
104104
<div class="ui tabular stackable menu navbar">
105105
{{if .Permission.CanRead $.UnitTypeCode}}
106106
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}">
@@ -172,6 +172,14 @@
172172
</div>
173173
{{end}}
174174
</div>
175+
{{else if .Permission.IsAdmin}}
176+
<div class="ui tabular stackable menu navbar">
177+
<div class="right menu">
178+
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">
179+
{{svg "octicon-tools"}} {{.i18n.Tr "repo.settings"}}
180+
</a>
181+
</div>
182+
</div>
175183
{{end}}
176184
</div>
177185
<div class="ui tabs divider"></div>

0 commit comments

Comments
 (0)