code.gitea.io/gitea@v1.21.7/models/migrations/v1_12/v128.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package v1_12 //nolint
     5  
     6  import (
     7  	"fmt"
     8  	"math"
     9  	"path/filepath"
    10  	"strings"
    11  	"time"
    12  
    13  	"code.gitea.io/gitea/modules/git"
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/setting"
    16  
    17  	"xorm.io/xorm"
    18  )
    19  
    20  func FixMergeBase(x *xorm.Engine) error {
    21  	type Repository struct {
    22  		ID        int64 `xorm:"pk autoincr"`
    23  		OwnerID   int64 `xorm:"UNIQUE(s) index"`
    24  		OwnerName string
    25  		LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
    26  		Name      string `xorm:"INDEX NOT NULL"`
    27  	}
    28  
    29  	type PullRequest struct {
    30  		ID         int64 `xorm:"pk autoincr"`
    31  		Index      int64
    32  		HeadRepoID int64 `xorm:"INDEX"`
    33  		BaseRepoID int64 `xorm:"INDEX"`
    34  		HeadBranch string
    35  		BaseBranch string
    36  		MergeBase  string `xorm:"VARCHAR(40)"`
    37  
    38  		HasMerged      bool   `xorm:"INDEX"`
    39  		MergedCommitID string `xorm:"VARCHAR(40)"`
    40  	}
    41  
    42  	limit := setting.Database.IterateBufferSize
    43  	if limit <= 0 {
    44  		limit = 50
    45  	}
    46  
    47  	ticker := time.NewTicker(5 * time.Second)
    48  	defer ticker.Stop()
    49  
    50  	count, err := x.Count(new(PullRequest))
    51  	if err != nil {
    52  		return err
    53  	}
    54  	log.Info("%d Pull Request(s) to migrate ...", count)
    55  
    56  	i := 0
    57  	start := 0
    58  	for {
    59  		prs := make([]PullRequest, 0, 50)
    60  		if err := x.Limit(limit, start).Asc("id").Find(&prs); err != nil {
    61  			return fmt.Errorf("Find: %w", err)
    62  		}
    63  		if len(prs) == 0 {
    64  			break
    65  		}
    66  
    67  		start += 50
    68  		for _, pr := range prs {
    69  			baseRepo := &Repository{ID: pr.BaseRepoID}
    70  			has, err := x.Table("repository").Get(baseRepo)
    71  			if err != nil {
    72  				return fmt.Errorf("Unable to get base repo %d %w", pr.BaseRepoID, err)
    73  			}
    74  			if !has {
    75  				log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
    76  				continue
    77  			}
    78  			userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName))
    79  			repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git")
    80  
    81  			gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
    82  
    83  			if !pr.HasMerged {
    84  				var err error
    85  				pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, "merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).RunStdString(&git.RunOpts{Dir: repoPath})
    86  				if err != nil {
    87  					var err2 error
    88  					pr.MergeBase, _, err2 = git.NewCommand(git.DefaultContext, "rev-parse").AddDynamicArguments(git.BranchPrefix + pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
    89  					if err2 != nil {
    90  						log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
    91  						continue
    92  					}
    93  				}
    94  			} else {
    95  				parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
    96  				if err != nil {
    97  					log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
    98  					continue
    99  				}
   100  				parents := strings.Split(strings.TrimSpace(parentsString), " ")
   101  				if len(parents) < 2 {
   102  					continue
   103  				}
   104  
   105  				refs := append([]string{}, parents[1:]...)
   106  				refs = append(refs, gitRefName)
   107  				cmd := git.NewCommand(git.DefaultContext, "merge-base").AddDashesAndList(refs...)
   108  
   109  				pr.MergeBase, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath})
   110  				if err != nil {
   111  					log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
   112  					continue
   113  				}
   114  			}
   115  			pr.MergeBase = strings.TrimSpace(pr.MergeBase)
   116  			x.ID(pr.ID).Cols("merge_base").Update(pr)
   117  			i++
   118  			select {
   119  			case <-ticker.C:
   120  				log.Info("%d/%d (%2.0f%%) Pull Request(s) migrated in %d batches. %d PRs Remaining ...", i, count, float64(i)/float64(count)*100, int(math.Ceil(float64(i)/float64(limit))), count-int64(i))
   121  			default:
   122  			}
   123  		}
   124  	}
   125  	log.Info("Completed migrating %d Pull Request(s) in: %d batches", count, int(math.Ceil(float64(i)/float64(limit))))
   126  	return nil
   127  }