mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 09:31:53 +01:00 
			
		
		
		
	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 <art27@cantab.net> * Update options/locale/locale_en-US.ini Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
		
							parent
							
								
									baed01f247
								
							
						
					
					
						commit
						1dbc58f742
					
				| @ -146,6 +146,7 @@ const ( | ||||
| 	RepositoryReady           RepositoryStatus = iota // a normal repository | ||||
| 	RepositoryBeingMigrated                           // repository is migrating | ||||
| 	RepositoryPendingTransfer                         // repository pending in ownership transfer state | ||||
| 	RepositoryBroken                                  // repository is in a permanently broken state | ||||
| ) | ||||
| 
 | ||||
| // TrustModelType defines the types of trust model for this repository | ||||
| @ -289,6 +290,11 @@ func (repo *Repository) IsBeingCreated() bool { | ||||
| 	return repo.IsBeingMigrated() | ||||
| } | ||||
| 
 | ||||
| // IsBroken indicates that repository is broken | ||||
| func (repo *Repository) IsBroken() bool { | ||||
| 	return repo.Status == RepositoryBroken | ||||
| } | ||||
| 
 | ||||
| // AfterLoad is invoked from XORM after setting the values of all fields of this object. | ||||
| func (repo *Repository) AfterLoad() { | ||||
| 	// FIXME: use models migration to solve all at once. | ||||
|  | ||||
| @ -522,14 +522,30 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") | ||||
| 
 | ||||
| 	// Disable everything when the repo is being created | ||||
| 	if ctx.Repo.Repository.IsBeingCreated() { | ||||
| 	if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() { | ||||
| 		ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch | ||||
| 		if !isHomeOrSettings { | ||||
| 			ctx.Redirect(ctx.Repo.RepoLink) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) | ||||
| 	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 = models.RepositoryBroken | ||||
| 			ctx.Repo.Repository.IsEmpty = true | ||||
| 			ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch | ||||
| 			// Only allow access to base of repo or settings | ||||
| 			if !isHomeOrSettings { | ||||
| 				ctx.Redirect(ctx.Repo.RepoLink) | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.ServerError("RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) | ||||
| 		return | ||||
| 	} | ||||
| @ -551,6 +567,17 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { | ||||
| 
 | ||||
| 	tags, err := ctx.Repo.GitRepo.GetTags(0, 0) | ||||
| 	if err != nil { | ||||
| 		if strings.Contains(err.Error(), "fatal: not a git repository ") { | ||||
| 			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 = models.RepositoryBroken | ||||
| 			ctx.Repo.Repository.IsEmpty = true | ||||
| 			ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch | ||||
| 			// Only allow access to base of repo or settings | ||||
| 			if !isHomeOrSettings { | ||||
| 				ctx.Redirect(ctx.Repo.RepoLink) | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.ServerError("GetTags", err) | ||||
| 		return | ||||
| 	} | ||||
| @ -919,6 +946,11 @@ func UnitTypes() func(ctx *Context) { | ||||
| // IssueTemplatesFromDefaultBranch checks for issue templates in the repo's default branch | ||||
| func (ctx *Context) IssueTemplatesFromDefaultBranch() []api.IssueTemplate { | ||||
| 	var issueTemplates []api.IssueTemplate | ||||
| 
 | ||||
| 	if ctx.Repo.Repository.IsEmpty { | ||||
| 		return issueTemplates | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.Repo.Commit == nil { | ||||
| 		var err error | ||||
| 		ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) | ||||
|  | ||||
| @ -946,6 +946,7 @@ clone_this_repo = Clone this repository | ||||
| create_new_repo_command = Creating a new repository on the command line | ||||
| push_exist_repo = Pushing an existing repository from the command line | ||||
| empty_message = This repository does not contain any content. | ||||
| broken_message = The git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository. | ||||
| 
 | ||||
| code = Code | ||||
| code.desc = Access source code, files, commits and branches. | ||||
|  | ||||
| @ -162,6 +162,14 @@ func ServCommand(ctx *context.PrivateContext) { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if repo.IsBroken() { | ||||
| 			ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{ | ||||
| 				Results: results, | ||||
| 				Err:     "Repository is in a broken state", | ||||
| 			}) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// We can shortcut at this point if the repo is a mirror | ||||
| 		if mode > models.AccessModeRead && repo.IsMirror { | ||||
| 			ctx.JSON(http.StatusForbidden, private.ErrServCommand{ | ||||
|  | ||||
| @ -10,7 +10,11 @@ | ||||
| 						{{.i18n.Tr "repo.archive.title"}} | ||||
| 					</div> | ||||
| 				{{end}} | ||||
| 				{{if .CanWriteCode}} | ||||
| 				{{if .Repository.IsBroken}} | ||||
| 						<div class="ui segment center"> | ||||
| 							{{.i18n.Tr "repo.broken_message"}} | ||||
| 						</div> | ||||
| 				{{else if .CanWriteCode}} | ||||
| 					<h4 class="ui top attached header"> | ||||
| 						{{.i18n.Tr "repo.quick_guide"}} | ||||
| 					</h4> | ||||
|  | ||||
| @ -40,7 +40,7 @@ | ||||
| 				{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{.BaseRepo.FullName}}</a></div>{{end}} | ||||
| 				{{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{.TemplateRepo.FullName}}</a></div>{{end}} | ||||
| 			</div> | ||||
| 			{{if not .IsBeingCreated}} | ||||
| 			{{if not (or .IsBeingCreated .IsBroken)}} | ||||
| 				<div class="repo-buttons"> | ||||
| 					{{if $.RepoTransfer}} | ||||
| 						<form method="post" action="{{$.RepoLink}}/action/accept_transfer?redirect_to={{$.RepoLink}}"> | ||||
| @ -100,7 +100,7 @@ | ||||
| 	</div><!-- end container --> | ||||
| {{end}} | ||||
| 	<div class="ui tabs container"> | ||||
| 		{{if not .Repository.IsBeingCreated}} | ||||
| 		{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}} | ||||
| 			<div class="ui tabular stackable menu navbar"> | ||||
| 				{{if .Permission.CanRead $.UnitTypeCode}} | ||||
| 				<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}"> | ||||
| @ -172,6 +172,14 @@ | ||||
| 					</div> | ||||
| 				{{end}} | ||||
| 			</div> | ||||
| 		{{else if .Permission.IsAdmin}} | ||||
| 			<div class="ui tabular stackable menu navbar"> | ||||
| 				<div class="right menu"> | ||||
| 					<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings"> | ||||
| 						{{svg "octicon-tools"}} {{.i18n.Tr "repo.settings"}} | ||||
| 					</a> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		{{end}} | ||||
| 	</div> | ||||
| 	<div class="ui tabs divider"></div> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user