Skip to content

Commit

Permalink
Ensure topics added using the API are added to the repository (#13285)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
zeripath and lunny authored Oct 24, 2020
1 parent 2fa4c4a commit 4099e4f
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 3 deletions.
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
68 changes: 68 additions & 0 deletions models/migrations/v157.go
Original file line number Diff line number Diff line change
@@ -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
}
33 changes: 30 additions & 3 deletions models/topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
Expand All @@ -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)
Expand Down

0 comments on commit 4099e4f

Please sign in to comment.