forked from Shiloh/githaven
76e9a4f701
Follow-up to #21352: when testing this out, I found out that the syntax for the `symbolic-ref` command was different than originally assumed in that PR. Never got around to submitting a PR until now. Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
92 lines
2.8 KiB
Go
92 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++
|
|
runOpts := &git.RunOpts{Dir: repo.RepoPath()}
|
|
|
|
_, _, defaultBranchErr := git.NewCommand(ctx, "rev-parse").AddDashesAndList(repo.DefaultBranch).RunStdString(runOpts)
|
|
|
|
head, _, headErr := git.NewCommand(ctx, "symbolic-ref", "--short", "HEAD").RunStdString(runOpts)
|
|
|
|
// 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(runOpts)
|
|
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")
|
|
} 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,
|
|
})
|
|
}
|