From 97b5cdc3f6373295e08a9d53d35c068a912374eb Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Fri, 31 Jan 2025 18:40:56 -0800
Subject: [PATCH] Fix possible bug when migrating issues/pull requests

---
 services/migrations/migrate.go | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go
index 51b22d6111..4914c4cb35 100644
--- a/services/migrations/migrate.go
+++ b/services/migrations/migrate.go
@@ -15,6 +15,7 @@ import (
 	repo_model "code.gitea.io/gitea/models/repo"
 	system_model "code.gitea.io/gitea/models/system"
 	user_model "code.gitea.io/gitea/models/user"
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/hostmatcher"
 	"code.gitea.io/gitea/modules/log"
@@ -328,6 +329,9 @@ func migrateRepository(_ context.Context, doer *user_model.User, downloader base
 		messenger("repo.migrate.migrating_issues")
 		issueBatchSize := uploader.MaxBatchInsertSize("issue")
 
+		// because when the migrating is running, some issues maybe removed, so after the next page
+		// some of issue maybe duplicated, so we need to record the inserted issue indexes
+		mapInsertedIssueIndexes := container.Set[int64]{}
 		for i := 1; ; i++ {
 			issues, isEnd, err := downloader.GetIssues(i, issueBatchSize)
 			if err != nil {
@@ -337,6 +341,14 @@ func migrateRepository(_ context.Context, doer *user_model.User, downloader base
 				log.Warn("migrating issues is not supported, ignored")
 				break
 			}
+			for i := 0; i < len(issues); i++ {
+				if mapInsertedIssueIndexes.Contains(issues[i].Number) {
+					issues = append(issues[:i], issues[i+1:]...)
+					i--
+					continue
+				}
+				mapInsertedIssueIndexes.Add(issues[i].Number)
+			}
 
 			if err := uploader.CreateIssues(issues...); err != nil {
 				return err
@@ -382,6 +394,7 @@ func migrateRepository(_ context.Context, doer *user_model.User, downloader base
 		log.Trace("migrating pull requests and comments")
 		messenger("repo.migrate.migrating_pulls")
 		prBatchSize := uploader.MaxBatchInsertSize("pullrequest")
+		mapInsertedIssueIndexes := container.Set[int64]{}
 		for i := 1; ; i++ {
 			prs, isEnd, err := downloader.GetPullRequests(i, prBatchSize)
 			if err != nil {
@@ -391,6 +404,14 @@ func migrateRepository(_ context.Context, doer *user_model.User, downloader base
 				log.Warn("migrating pull requests is not supported, ignored")
 				break
 			}
+			for i := 0; i < len(prs); i++ {
+				if mapInsertedIssueIndexes.Contains(prs[i].Number) {
+					prs = append(prs[:i], prs[i+1:]...)
+					i--
+					continue
+				}
+				mapInsertedIssueIndexes.Add(prs[i].Number)
+			}
 
 			if err := uploader.CreatePullRequests(prs...); err != nil {
 				return err