0d25292fbc
Backport #21791 There was a bug introduced in #21352 due to a change of behaviour caused by #19280. This causes a panic on running the default doctor checks because the panic introduced by #19280 assumes that the only way opts.StdOut and opts.Stderr can be set in RunOpts is deliberately. Unfortunately, when running a git.Command the provided RunOpts can be set, therefore if you share a common set of RunOpts these two values can be set by the previous commands. This PR stops using common RunOpts for the commands in that doctor check but secondly stops RunCommand variants from changing the provided RunOpts. Signed-off-by: Andrew Thornton <art27@cantab.net>
89 lines
2.8 KiB
Go
89 lines
2.8 KiB
Go
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package doctor
|
|
|
|
import (
|
|
"context"
|
|
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/log"
|
|
)
|
|
|
|
func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool) error {
|
|
numRepos := 0
|
|
numHeadsBroken := 0
|
|
numDefaultBranchesBroken := 0
|
|
numReposUpdated := 0
|
|
err := iterateRepositories(ctx, func(repo *repo_model.Repository) error {
|
|
numRepos++
|
|
_, _, defaultBranchErr := git.NewCommand(ctx, "rev-parse").AddDashesAndList(repo.DefaultBranch).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
|
|
|
|
head, _, headErr := git.NewCommand(ctx, "symbolic-ref", "--short", "HEAD").RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
|
|
|
|
// what we expect: default branch is valid, and HEAD points to it
|
|
if headErr == nil && defaultBranchErr == nil && head == repo.DefaultBranch {
|
|
return nil
|
|
}
|
|
|
|
if headErr != nil {
|
|
numHeadsBroken++
|
|
}
|
|
if defaultBranchErr != nil {
|
|
numDefaultBranchesBroken++
|
|
}
|
|
|
|
// if default branch is broken, let the user fix that in the UI
|
|
if defaultBranchErr != nil {
|
|
logger.Warn("Default branch for %s/%s doesn't point to a valid commit", repo.OwnerName, repo.Name)
|
|
return nil
|
|
}
|
|
|
|
// if we're not autofixing, that's all we can do
|
|
if !autofix {
|
|
return nil
|
|
}
|
|
|
|
// otherwise, let's try fixing HEAD
|
|
err := git.NewCommand(ctx, "symbolic-ref").AddDashesAndList("HEAD", git.BranchPrefix+repo.DefaultBranch).Run(&git.RunOpts{Dir: repo.RepoPath()})
|
|
if err != nil {
|
|
logger.Warn("Failed to fix HEAD for %s/%s: %v", repo.OwnerName, repo.Name, err)
|
|
return nil
|
|
}
|
|
numReposUpdated++
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
logger.Critical("Error when fixing repo HEADs: %v", err)
|
|
}
|
|
|
|
if autofix {
|
|
logger.Info("Out of %d repos, HEADs for %d are now fixed and HEADS for %d are still broken", numRepos, numReposUpdated, numDefaultBranchesBroken+numHeadsBroken-numReposUpdated)
|
|
} else {
|
|
if numHeadsBroken == 0 && numDefaultBranchesBroken == 0 {
|
|
logger.Info("All %d repos have their HEADs in the correct state", numRepos)
|
|
} else {
|
|
if numHeadsBroken == 0 && numDefaultBranchesBroken != 0 {
|
|
logger.Critical("Default branches are broken for %d/%d repos", numDefaultBranchesBroken, numRepos)
|
|
} else if numHeadsBroken != 0 && numDefaultBranchesBroken == 0 {
|
|
logger.Warn("HEADs are broken for %d/%d repos", numHeadsBroken, numRepos)
|
|
} else {
|
|
logger.Critical("Out of %d repos, HEADS are broken for %d and default branches are broken for %d", numRepos, numHeadsBroken, numDefaultBranchesBroken)
|
|
}
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func init() {
|
|
Register(&Check{
|
|
Title: "Synchronize repo HEADs",
|
|
Name: "synchronize-repo-heads",
|
|
IsDefault: true,
|
|
Run: synchronizeRepoHeads,
|
|
Priority: 7,
|
|
})
|
|
}
|