code.gitea.io/gitea@v1.21.7/models/migrations/v1_12/v134.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 RefixMergeBase(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  	count, err := x.Where("has_merged = ?", true).Count(new(PullRequest))
    50  	if err != nil {
    51  		return err
    52  	}
    53  	log.Info("%d Merged Pull Request(s) to migrate ...", count)
    54  
    55  	i := 0
    56  	start := 0
    57  	for {
    58  		prs := make([]PullRequest, 0, 50)
    59  		if err := x.Limit(limit, start).Asc("id").Where("has_merged = ?", true).Find(&prs); err != nil {
    60  			return fmt.Errorf("Find: %w", err)
    61  		}
    62  		if len(prs) == 0 {
    63  			break
    64  		}
    65  
    66  		start += 50
    67  		for _, pr := range prs {
    68  			baseRepo := &Repository{ID: pr.BaseRepoID}
    69  			has, err := x.Table("repository").Get(baseRepo)
    70  			if err != nil {
    71  				return fmt.Errorf("Unable to get base repo %d %w", pr.BaseRepoID, err)
    72  			}
    73  			if !has {
    74  				log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
    75  				continue
    76  			}
    77  			userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName))
    78  			repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git")
    79  
    80  			gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
    81  
    82  			parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
    83  			if err != nil {
    84  				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)
    85  				continue
    86  			}
    87  			parents := strings.Split(strings.TrimSpace(parentsString), " ")
    88  			if len(parents) < 3 {
    89  				continue
    90  			}
    91  
    92  			// we should recalculate
    93  			refs := append([]string{}, parents[1:]...)
    94  			refs = append(refs, gitRefName)
    95  			cmd := git.NewCommand(git.DefaultContext, "merge-base").AddDashesAndList(refs...)
    96  
    97  			pr.MergeBase, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath})
    98  			if err != nil {
    99  				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)
   100  				continue
   101  			}
   102  			pr.MergeBase = strings.TrimSpace(pr.MergeBase)
   103  			x.ID(pr.ID).Cols("merge_base").Update(pr)
   104  			i++
   105  			select {
   106  			case <-ticker.C:
   107  				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))
   108  			default:
   109  			}
   110  		}
   111  	}
   112  
   113  	log.Info("Completed migrating %d Pull Request(s) in: %d batches", count, int(math.Ceil(float64(i)/float64(limit))))
   114  	return nil
   115  }