Skip to content

Data migration ('tags' to 'topics') for projects [RUN ALL RSPEC]

Introduction

In GitLab, a project can have topics and tags (git tags) on its repository. Unfortunately, topics appear in various places under the name tags, which leads to a lot of confusion. As discussed in #328226 (closed), this confusion is to be cleared up. So I submitted the MR !60834 (closed) for that. However, the MR was too big. So I closed the MR and will submit several separate MRs instead.

What does this MR do?

This MR changes the context of the used acts_as_taggable_on gem from tags (default) to topics. In addition, this MR includes the data migration required for this. To ensure that nothing changes for other areas of the source code for the time being, appropriate aliases are temporarily added. These aliases will be eliminated in a later MR in the process of the 'tags -> topics' migration.

Details

Before this MR:

The Project model contains the following definition:

class Project < ApplicationRecord {
  ...
  acts_as_ordered_taggable # shortcut for `acts_as_ordered_taggable_on :tags`
  ...
}

This enables the following functionality through the gem:

# Edit topics
@project.tag_list = "topic1, topic2, topic3"
# Get topics
@project.tag_list # => ["topic1", "topic2", "topic3"]
@project.tags # => [#<ActsAsTaggableOn::Tag:... name: "topic1">, #<ActsAsTaggableOn::Tag:... name: "topic2">, #<ActsAsTaggableOn::Tag:... name: "topic3">]
@project.topics # => ["topic1", "topic2", "topic3"] # alias for `tag_list`

Changes by this MR:

The context on acts_as_ordered_taggable_on is changed from :tags (default) to :topics:

class Project < ApplicationRecord {
  ...
  acts_as_ordered_taggable_on :topics
  ...
}

This enables the following functionality through the gem:

# Edit topics
@project.topic_list = "topic1, topic2, topic3"
# Get topics
@project.topic_list # => ["topic1", "topic2", "topic3"]
@project.topics # => [#<ActsAsTaggableOn::Tag:... name: "topic1">, #<ActsAsTaggableOn::Tag:... name: "topic2">, #<ActsAsTaggableOn::Tag:... name: "topic3">]

Due to the aliases, the new and the old functionality are now available:

# Edit topics
@project.topic_list = "topic1, topic2, topic3"
@project.tag_list = "topic1, topic2, topic3"
# Get topics
@project.topic_list # => ["topic1", "topic2", "topic3"]
@project.tag_list # => ["topic1", "topic2", "topic3"]
@project.topics # => [#<ActsAsTaggableOn::Tag:... name: "topic1">, #<ActsAsTaggableOn::Tag:... name: "topic2">, #<ActsAsTaggableOn::Tag:... name: "topic3">]
@project.tags # => [#<ActsAsTaggableOn::Tag:... name: "topic1">, #<ActsAsTaggableOn::Tag:... name: "topic2">, #<ActsAsTaggableOn::Tag:... name: "topic3">]

🛠 with at Siemens

/cc @bufferoverflow

Database review

DB Migration:

== 20210511095657 AddTemporaryIndexForProjectTopicsToTaggings: migrating ======
-- transaction_open?()
   -> 0.0001s
-- index_exists?(:taggings, :id, {:where=>"taggable_type = 'Project' AND context = 'tags'", :name=>"tmp_index_taggings_on_id_where_taggable_type_project_and_tags", :algorithm=>:concurrently})
   -> 0.0096s
-- execute("SET statement_timeout TO 0")
   -> 0.0023s
-- add_index(:taggings, :id, {:where=>"taggable_type = 'Project' AND context = 'tags'", :name=>"tmp_index_taggings_on_id_where_taggable_type_project_and_tags", :algorithm=>:concurrently})
   -> 0.0220s
-- execute("RESET ALL")
   -> 0.0042s
== 20210511095657 AddTemporaryIndexForProjectTopicsToTaggings: migrated (0.0410s) 

== 20210511095658 ScheduleMigrateProjectTaggingsContextFromTagsToTopics: migrating 
-- Scheduled 1 MigrateProjectTaggingsContextFromTagsToTopics jobs with a maximum of 30000 records per batch and an interval of 120 seconds.

The migration is expected to take at least 120 seconds. Expect all jobs to have completed after 2021-05-17 08:05:29 UTC."
== 20210511095658 ScheduleMigrateProjectTaggingsContextFromTagsToTopics: migrated (0.1006s) 

== 20210517075444 RemoveTemporaryIndexForProjectTopicsToTaggings: migrating ===
-- transaction_open?()
   -> 0.0003s
-- indexes(:taggings)
   -> 0.0086s
-- remove_index(:taggings, {:algorithm=>:concurrently, :name=>"tmp_index_taggings_on_id_where_taggable_type_project_and_tags"})
   -> 0.0031s
== 20210517075444 RemoveTemporaryIndexForProjectTopicsToTaggings: migrated (0.0186s) 

DB Rollback:

== 20210517075444 RemoveTemporaryIndexForProjectTopicsToTaggings: reverting ===
-- transaction_open?()
   -> 0.0000s
-- index_exists?(:taggings, :id, {:where=>"taggable_type = 'Project' AND context = 'tags'", :name=>"tmp_index_taggings_on_id_where_taggable_type_project_and_tags", :algorithm=>:concurrently})
   -> 0.0055s
-- execute("SET statement_timeout TO 0")
   -> 0.0008s
-- add_index(:taggings, :id, {:where=>"taggable_type = 'Project' AND context = 'tags'", :name=>"tmp_index_taggings_on_id_where_taggable_type_project_and_tags", :algorithm=>:concurrently})
   -> 0.0095s
-- execute("RESET ALL")
   -> 0.0008s
== 20210517075444 RemoveTemporaryIndexForProjectTopicsToTaggings: reverted (0.0185s) 

== 20210511095658 ScheduleMigrateProjectTaggingsContextFromTagsToTopics: reverting 
== 20210511095658 ScheduleMigrateProjectTaggingsContextFromTagsToTopics: reverted (0.0000s) 

== 20210511095657 AddTemporaryIndexForProjectTopicsToTaggings: reverting ======
-- transaction_open?()
   -> 0.0000s
-- indexes(:taggings)
   -> 0.0079s
-- execute("SET statement_timeout TO 0")
   -> 0.0026s
-- remove_index(:taggings, {:algorithm=>:concurrently, :name=>"tmp_index_taggings_on_id_where_taggable_type_project_and_tags"})
   -> 0.0047s
-- execute("RESET ALL")
   -> 0.0011s
== 20210511095657 AddTemporaryIndexForProjectTopicsToTaggings: reverted (0.0184s) 

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • [-] Label as security and @ mention @gitlab-com/gl-security/appsec
  • [-] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • [-] Security reports checked/validated by a reviewer from the AppSec team
Edited by Jonas Wälter

Merge request reports