Migration to write fullpath in all repository configs

In https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/16027 it was
added to write `gitlab.fullpath` in the git config of all
repositories. But this only writes them on move or migrate to hashed
storage.

This adds a migration that writes the fullpath to all the
repositories.

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/41776
This commit is contained in:
Toon Claes 2018-10-12 14:40:44 +02:00
parent 6c83c2d8b9
commit ffdb3f26e7
3 changed files with 211 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
title: Migration to write fullpath in all repository configs
merge_request: 22322
author:
type: other

View file

@ -0,0 +1,136 @@
# frozen_string_literal: true
class BackfillStoreProjectFullPathInRepo < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
class Repository
attr_reader :storage
def initialize(storage, relative_path)
@storage = storage
@relative_path = relative_path
end
def gitaly_repository
Gitaly::Repository.new(storage_name: @storage, relative_path: @relative_path)
end
end
module Storage
class HashedProject
attr_accessor :project
ROOT_PATH_PREFIX = '@hashed'.freeze
def initialize(project)
@project = project
end
def disk_path
"#{ROOT_PATH_PREFIX}/#{disk_hash[0..1]}/#{disk_hash[2..3]}/#{disk_hash}"
end
def disk_hash
@disk_hash ||= Digest::SHA2.hexdigest(project.id.to_s) if project.id
end
end
class LegacyProject
attr_accessor :project
def initialize(project)
@project = project
end
def disk_path
project.full_path
end
end
end
module Routable
extend ActiveSupport::Concern
def full_path
@full_path ||= build_full_path
end
def build_full_path
if parent && path
parent.full_path + '/' + path
else
path
end
end
end
class Namespace < ActiveRecord::Base
self.table_name = 'namespaces'
include Routable
belongs_to :parent, class_name: "Namespace"
end
class Project < ActiveRecord::Base
self.table_name = 'projects'
include Routable
include EachBatch
FULLPATH_CONFIG_KEY = 'gitlab.fullpath'
belongs_to :namespace
delegate :disk_path, to: :storage
alias_method :parent, :namespace
def add_fullpath_config
entries = { FULLPATH_CONFIG_KEY => full_path }
repository_service.set_config(entries)
end
def remove_fullpath_config
repository_service.delete_config([FULLPATH_CONFIG_KEY])
end
def storage
@storage ||=
if hashed_storage?
Storage::HashedProject.new(self)
else
Storage::LegacyProject.new(self)
end
end
def hashed_storage?
self.storage_version && self.storage_version >= 1
end
def repository
@repository ||= Repository.new(repository_storage, disk_path + '.git')
end
def repository_service
@repository_service ||= Gitlab::GitalyClient::RepositoryService.new(repository)
end
end
def up
Project.each_batch do |batch|
batch.each do |project|
project.add_fullpath_config
end
end
end
def down
Project.each_batch do |batch|
batch.each do |project|
project.remove_fullpath_config
end
end
end
end

View file

@ -0,0 +1,70 @@
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181010133639_backfill_store_project_full_path_in_repo.rb')
describe BackfillStoreProjectFullPathInRepo, :migration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:group) { namespaces.create!(name: 'foo', path: 'foo') }
let(:subgroup) { namespaces.create!(name: 'bar', path: 'bar', parent_id: group.id) }
subject(:migration) { described_class.new }
describe '#up' do
shared_examples_for 'writes the full path to git config' do
it 'writes the git config' do
expect_any_instance_of(Gitlab::GitalyClient::RepositoryService)
.to receive(:set_config).with('gitlab.fullpath' => expected_path)
migration.up
end
context 'legacy storage' do
it 'finds the repository at the correct location' do
Project.find(project.id).create_repository
expect { migration.up }.not_to raise_error
end
end
context 'hashed storage' do
it 'finds the repository at the correct location' do
project.update_attribute(:storage_version, 1)
Project.find(project.id).create_repository
expect { migration.up }.not_to raise_error
end
end
end
context 'project in group' do
let!(:project) { projects.create!(namespace_id: group.id, name: 'baz', path: 'baz') }
let(:expected_path) { 'foo/baz' }
it_behaves_like 'writes the full path to git config'
end
context 'project in subgroup' do
let!(:project) { projects.create!(namespace_id: subgroup.id, name: 'baz', path: 'baz') }
let(:expected_path) { 'foo/bar/baz' }
it_behaves_like 'writes the full path to git config'
end
end
describe '#down' do
context 'project in group' do
let!(:project) { projects.create!(namespace_id: group.id, name: 'baz', path: 'baz') }
it 'deletes the gitlab full config value' do
expect_any_instance_of(Gitlab::GitalyClient::RepositoryService)
.to receive(:delete_config).with(['gitlab.fullpath'])
migration.down
end
end
end
end