Ensure topics added using the API are added to the repository (#13285)
* Ensure topics added using the API are added to the repository Fix #12426 Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
		
							parent
							
								
									2fa4c4ad3a
								
							
						
					
					
						commit
						4099e4f1b6
					
				
					 3 changed files with 100 additions and 3 deletions
				
			
		|  | @ -248,6 +248,8 @@ var migrations = []Migration{ | |||
| 	NewMigration("add changed_protected_files column for pull_request table", addChangedProtectedFilesPullRequestColumn), | ||||
| 	// v156 -> v157
 | ||||
| 	NewMigration("fix publisher ID for tag releases", fixPublisherIDforTagReleases), | ||||
| 	// v157 -> v158
 | ||||
| 	NewMigration("ensure repo topics are up-to-date", fixRepoTopics), | ||||
| } | ||||
| 
 | ||||
| // GetCurrentDBVersion returns the current db version
 | ||||
|  |  | |||
							
								
								
									
										68
									
								
								models/migrations/v157.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								models/migrations/v157.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| // 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 ( | ||||
| 	"xorm.io/xorm" | ||||
| ) | ||||
| 
 | ||||
| func fixRepoTopics(x *xorm.Engine) error { | ||||
| 
 | ||||
| 	type Topic struct { | ||||
| 		ID        int64  `xorm:"pk autoincr"` | ||||
| 		Name      string `xorm:"UNIQUE VARCHAR(25)"` | ||||
| 		RepoCount int | ||||
| 	} | ||||
| 
 | ||||
| 	type RepoTopic struct { | ||||
| 		RepoID  int64 `xorm:"pk"` | ||||
| 		TopicID int64 `xorm:"pk"` | ||||
| 	} | ||||
| 
 | ||||
| 	type Repository struct { | ||||
| 		ID     int64    `xorm:"pk autoincr"` | ||||
| 		Topics []string `xorm:"TEXT JSON"` | ||||
| 	} | ||||
| 
 | ||||
| 	const batchSize = 100 | ||||
| 	sess := x.NewSession() | ||||
| 	defer sess.Close() | ||||
| 	repos := make([]*Repository, 0, batchSize) | ||||
| 	topics := make([]string, 0, batchSize) | ||||
| 	for start := 0; ; start += batchSize { | ||||
| 		repos = repos[:0] | ||||
| 
 | ||||
| 		if err := sess.Begin(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if err := sess.Limit(batchSize, start).Find(&repos); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if len(repos) == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		for _, repo := range repos { | ||||
| 			topics = topics[:0] | ||||
| 			if err := sess.Select("name").Table("topic"). | ||||
| 				Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id"). | ||||
| 				Where("repo_topic.repo_id = ?", repo.ID).Desc("topic.repo_count").Find(&topics); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			repo.Topics = topics | ||||
| 			if _, err := sess.ID(repo.ID).Cols("topics").Update(repo); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if err := sess.Commit(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -197,10 +197,13 @@ func FindTopics(opts *FindTopicOptions) (topics []*Topic, err error) { | |||
| 
 | ||||
| // GetRepoTopicByName retrives topic from name for a repo if it exist
 | ||||
| func GetRepoTopicByName(repoID int64, topicName string) (*Topic, error) { | ||||
| 	return getRepoTopicByName(x, repoID, topicName) | ||||
| } | ||||
| func getRepoTopicByName(e Engine, repoID int64, topicName string) (*Topic, error) { | ||||
| 	var cond = builder.NewCond() | ||||
| 	var topic Topic | ||||
| 	cond = cond.And(builder.Eq{"repo_topic.repo_id": repoID}).And(builder.Eq{"topic.name": topicName}) | ||||
| 	sess := x.Table("topic").Where(cond) | ||||
| 	sess := e.Table("topic").Where(cond) | ||||
| 	sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") | ||||
| 	has, err := sess.Get(&topic) | ||||
| 	if has { | ||||
|  | @ -211,7 +214,13 @@ func GetRepoTopicByName(repoID int64, topicName string) (*Topic, error) { | |||
| 
 | ||||
| // AddTopic adds a topic name to a repository (if it does not already have it)
 | ||||
| func AddTopic(repoID int64, topicName string) (*Topic, error) { | ||||
| 	topic, err := GetRepoTopicByName(repoID, topicName) | ||||
| 	sess := x.NewSession() | ||||
| 	defer sess.Close() | ||||
| 	if err := sess.Begin(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	topic, err := getRepoTopicByName(sess, repoID, topicName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -220,7 +229,25 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { | |||
| 		return topic, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return addTopicByNameToRepo(x, repoID, topicName) | ||||
| 	topic, err = addTopicByNameToRepo(sess, repoID, topicName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	topicNames := make([]string, 0, 25) | ||||
| 	if err := sess.Select("name").Table("topic"). | ||||
| 		Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id"). | ||||
| 		Where("repo_topic.repo_id = ?", repoID).Desc("topic.repo_count").Find(&topicNames); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{ | ||||
| 		Topics: topicNames, | ||||
| 	}); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return topic, sess.Commit() | ||||
| } | ||||
| 
 | ||||
| // DeleteTopic removes a topic name from a repository (if it has it)
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue