mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-01 06:48:56 +00:00
2a565478d1
Unfortunately some old repositories can have tags with empty Tagger, Commit or Author. Go-Git variants will always have empty values for these whereas the native git variant leaves them at nil. The simplest solution is just to always have these set to empty Signatures. v156 migration also makes the incorrect assumption that these cannot be empty. Therefore add some handling to this and add logging and adjust broken logging elsewhere in this migration. Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
178 lines
5.3 KiB
Go
178 lines
5.3 KiB
Go
// Copyright 2020 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 migrations
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
|
|
"xorm.io/xorm"
|
|
)
|
|
|
|
// Copy paste from models/repo.go because we cannot import models package
|
|
func repoPath(userName, repoName string) string {
|
|
return filepath.Join(userPath(userName), strings.ToLower(repoName)+".git")
|
|
}
|
|
|
|
func userPath(userName string) string {
|
|
return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
|
|
}
|
|
|
|
func fixPublisherIDforTagReleases(x *xorm.Engine) error {
|
|
type Release struct {
|
|
ID int64
|
|
RepoID int64
|
|
Sha1 string
|
|
TagName string
|
|
PublisherID int64
|
|
}
|
|
|
|
type Repository struct {
|
|
ID int64
|
|
OwnerID int64
|
|
OwnerName string
|
|
Name string
|
|
}
|
|
|
|
type User struct {
|
|
ID int64
|
|
Name string
|
|
Email string
|
|
}
|
|
|
|
const batchSize = 100
|
|
sess := x.NewSession()
|
|
defer sess.Close()
|
|
|
|
var (
|
|
repo *Repository
|
|
gitRepo *git.Repository
|
|
user *User
|
|
)
|
|
defer func() {
|
|
if gitRepo != nil {
|
|
gitRepo.Close()
|
|
}
|
|
}()
|
|
for start := 0; ; start += batchSize {
|
|
releases := make([]*Release, 0, batchSize)
|
|
|
|
if err := sess.Begin(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := sess.Limit(batchSize, start).
|
|
Where("publisher_id = 0 OR publisher_id is null").
|
|
Asc("repo_id", "id").Where("is_tag=?", true).
|
|
Find(&releases); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(releases) == 0 {
|
|
break
|
|
}
|
|
|
|
for _, release := range releases {
|
|
if repo == nil || repo.ID != release.RepoID {
|
|
if gitRepo != nil {
|
|
gitRepo.Close()
|
|
gitRepo = nil
|
|
}
|
|
repo = new(Repository)
|
|
has, err := sess.ID(release.RepoID).Get(repo)
|
|
if err != nil {
|
|
log.Error("Error whilst loading repository[%d] for release[%d] with tag name %s. Error: %v", release.RepoID, release.ID, release.TagName, err)
|
|
return err
|
|
} else if !has {
|
|
log.Warn("Release[%d] is orphaned and refers to non-existing repository %d", release.ID, release.RepoID)
|
|
log.Warn("This release should be deleted")
|
|
continue
|
|
}
|
|
|
|
if repo.OwnerName == "" {
|
|
// v120.go migration may not have been run correctly - we'll just replicate it here
|
|
// because this appears to be a common-ish problem.
|
|
if _, err := sess.Exec("UPDATE repository SET owner_name = (SELECT name FROM `user` WHERE `user`.id = repository.owner_id)"); err != nil {
|
|
log.Error("Error whilst updating repository[%d] owner name", repo.ID)
|
|
return err
|
|
}
|
|
|
|
if _, err := sess.ID(release.RepoID).Get(repo); err != nil {
|
|
log.Error("Error whilst loading repository[%d] for release[%d] with tag name %s. Error: %v", release.RepoID, release.ID, release.TagName, err)
|
|
return err
|
|
}
|
|
}
|
|
gitRepo, err = git.OpenRepository(repoPath(repo.OwnerName, repo.Name))
|
|
if err != nil {
|
|
log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
commit, err := gitRepo.GetTagCommit(release.TagName)
|
|
if err != nil {
|
|
if git.IsErrNotExist(err) {
|
|
log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
|
|
continue
|
|
}
|
|
log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
|
return fmt.Errorf("GetTagCommit: %v", err)
|
|
}
|
|
|
|
if commit.Author.Email == "" {
|
|
log.Warn("Tag: %s in Repo[%d]%s/%s does not have a tagger.", release.TagName, repo.ID, repo.OwnerName, repo.Name)
|
|
commit, err = gitRepo.GetCommit(commit.ID.String())
|
|
if err != nil {
|
|
if git.IsErrNotExist(err) {
|
|
log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
|
|
continue
|
|
}
|
|
log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
|
return fmt.Errorf("GetCommit: %v", err)
|
|
}
|
|
}
|
|
|
|
if commit.Author.Email == "" {
|
|
log.Warn("Tag: %s in Repo[%d]%s/%s does not have a Tagger and its underlying commit does not have an Author either!", release.TagName, repo.ID, repo.OwnerName, repo.Name)
|
|
continue
|
|
}
|
|
|
|
if user == nil || !strings.EqualFold(user.Email, commit.Author.Email) {
|
|
user = new(User)
|
|
_, err = sess.Where("email=?", commit.Author.Email).Get(user)
|
|
if err != nil {
|
|
log.Error("Error whilst getting commit author by email: %s for Tag: %s in [%d]%s/%s. Error: %v", commit.Author.Email, release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
|
return err
|
|
}
|
|
|
|
user.Email = commit.Author.Email
|
|
}
|
|
|
|
if user.ID <= 0 {
|
|
continue
|
|
}
|
|
|
|
release.PublisherID = user.ID
|
|
if _, err := sess.ID(release.ID).Cols("publisher_id").Update(release); err != nil {
|
|
log.Error("Error whilst updating publisher[%d] for release[%d] with tag name %s. Error: %v", release.PublisherID, release.ID, release.TagName, err)
|
|
return err
|
|
}
|
|
}
|
|
if gitRepo != nil {
|
|
gitRepo.Close()
|
|
}
|
|
|
|
if err := sess.Commit(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|