diff --git a/CHANGELOG b/CHANGELOG index 2f93fcdbaa0cf8aec677e2cb21ce44094a2e86bb..099e0d8381553ef5ce2c97ffb5cf76e7a8970570 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -31,6 +31,7 @@ v 8.10.0 (unreleased) - Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Add basic system information like memory and disk usage to the admin panel + - Don't garbage collect commits that have related DB records like comments v 8.9.5 (unreleased) - Improve the request / withdraw access button. !4860 diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 10324bf22579ccffa360b974198fc45465adfbe0..fa4071e2482f236fc8dccf984255ff1cee45347e 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -16,6 +16,7 @@ module Ci # Invalidate object and save if when touched after_touch :update_state + after_save :keep_around_commits def self.truncate_sha(sha) sha[0...8] @@ -212,5 +213,10 @@ module Ci self.duration = statuses.latest.duration save end + + def keep_around_commits + project.repository.keep_around(self.sha) + project.repository.keep_around(self.before_sha) + end end end diff --git a/app/models/ci/trigger_request.rb b/app/models/ci/trigger_request.rb index b69ae37668c89de576464f679abfb249202fb8d7..fcf2b6dc5e221ab2d6cdb7c7242de42472ac523f 100644 --- a/app/models/ci/trigger_request.rb +++ b/app/models/ci/trigger_request.rb @@ -1,7 +1,7 @@ module Ci class TriggerRequest < ActiveRecord::Base extend Ci::Model - + belongs_to :trigger, class_name: 'Ci::Trigger' belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id has_many :builds, class_name: 'Ci::Build' diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 5ebc8f0c99feb4a1461e7772bfce4f4f70cd04a0..cb0f871897a346b5dd7a954b3a3ac6ad1d65e0f3 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -117,6 +117,8 @@ class MergeRequest < ActiveRecord::Base scope :join_project, -> { joins(:target_project) } scope :references_project, -> { references(:target_project) } + after_save :keep_around_commit + def self.reference_prefix '!' end @@ -536,12 +538,12 @@ class MergeRequest < ActiveRecord::Base "refs/merge-requests/#{iid}/head" end - def ref_is_fetched? - File.exist?(File.join(project.repository.path_to_repo, ref_path)) + def ref_fetched? + project.repository.ref_exists?(ref_path) end def ensure_ref_fetched - fetch_ref unless ref_is_fetched? + fetch_ref unless ref_fetched? end def in_locked_state @@ -600,4 +602,8 @@ class MergeRequest < ActiveRecord::Base def can_be_cherry_picked? merge_commit end + + def keep_around_commit + project.repository.keep_around(self.merge_commit_sha) + end end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 86331a33c051db7afbf978e2e342d42306a86f24..0fcde6fc8f13d13d0003832234c636d9f3f79e56 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -24,6 +24,7 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_diffs after_create :reload_content, unless: :importing? + after_save :keep_around_commit def reload_content reload_commits @@ -145,7 +146,11 @@ class MergeRequestDiff < ActiveRecord::Base end new_attributes[:st_diffs] = new_diffs - new_attributes[:base_commit_sha] = self.repository.merge_base(self.head, self.base) + + base_commit_sha = self.repository.merge_base(self.head, self.base) + new_attributes[:base_commit_sha] = base_commit_sha + + self.repository.keep_around(base_commit_sha) update_columns_serialized(new_attributes) end @@ -217,4 +222,8 @@ class MergeRequestDiff < ActiveRecord::Base update_columns(new_attributes.merge(updated_at: current_time_from_proper_timezone)) reload end + + def keep_around_commit + self.repository.keep_around(self.base_commit_sha) + end end diff --git a/app/models/note.rb b/app/models/note.rb index c2bb117eb03c5cb23809b111d9fa3ee0908949e6..81b5c47b7381551cc34c2e473826886b3ba07aa8 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -66,6 +66,7 @@ class Note < ActiveRecord::Base end before_validation :clear_blank_line_code! + after_save :keep_around_commit class << self def model_name @@ -215,4 +216,10 @@ class Note < ActiveRecord::Base original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1] Gitlab::AwardEmoji.normalize_emoji_name(original_name) end + + private + + def keep_around_commit + project.repository.keep_around(self.commit_id) + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index 11ecb281a559a7522806746a247731936ea19166..e3ad33a896a36b7fb91ca18d995b619a2fb03117 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -203,6 +203,26 @@ class Repository branch_names.include?(branch_name) end + def ref_exists?(ref) + rugged.references.exist?(ref) + end + + def keep_around(sha) + return unless sha && commit(sha) + + return if kept_around?(sha) + + rugged.references.create(keep_around_ref_name(sha), sha) + end + + def kept_around?(sha) + ref_exists?(keep_around_ref_name(sha)) + end + + def keep_around_ref_name(sha) + "refs/keep-around/#{sha}" + end + def tag_names cache.fetch(:tag_names) { raw_repository.tag_names } end diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index 375f195dba7234de5c5221b220faa5a4e33b7c2b..a2df899d012caac8504228875d5274fb8019ec01 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -9,6 +9,8 @@ class SentNotification < ActiveRecord::Base validates :commit_id, presence: true, if: :for_commit? validates :line_code, line_code: true, allow_blank: true + after_save :keep_around_commit + class << self def reply_key SecureRandom.hex(16) @@ -67,4 +69,10 @@ class SentNotification < ActiveRecord::Base def to_param self.reply_key end + + private + + def keep_around_commit + project.repository.keep_around(self.commit_id) + end end diff --git a/app/models/todo.rb b/app/models/todo.rb index 3ba67078d481572f8678ef8755c3bb7211fad836..ac3fdbc7f3baab63054af7ffbfee7064b87d8d36 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -37,6 +37,8 @@ class Todo < ActiveRecord::Base state :done end + after_save :keep_around_commit + def build_failed? action == BUILD_FAILED end @@ -73,4 +75,10 @@ class Todo < ActiveRecord::Base target.to_reference end end + + private + + def keep_around_commit + project.repository.keep_around(self.commit_id) + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 3b199f4d98d91834dbd592e9788f35e9c891fe37..ceb4d64698f5ee87fbde99be18acd54ce9966966 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -464,7 +464,7 @@ describe MergeRequest, models: true do context 'when it is not broken and has no conflicts' do it 'is marked as mergeable' do allow(subject).to receive(:broken?) { false } - allow(project).to receive_message_chain(:repository, :can_be_merged?) { true } + allow(project.repository).to receive(:can_be_merged?) { true } expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('can_be_merged') end @@ -481,7 +481,7 @@ describe MergeRequest, models: true do context 'when it has conflicts' do before do allow(subject).to receive(:broken?) { false } - allow(project).to receive_message_chain(:repository, :can_be_merged?) { false } + allow(project.repository).to receive(:can_be_merged?) { false } end it 'becomes unmergeable' do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 285ab19cfafd9d93526ff1193bd229637b456a27..6549791f6758de24d493f919fb2d505f859d8ab4 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -70,6 +70,10 @@ describe Note, models: true do it "should be recognized by #for_commit?" do expect(note).to be_for_commit end + + it "keeps the commit around" do + expect(note.project.repository.kept_around?(commit.id)).to be_truthy + end end describe 'authorization' do diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 851b8b241d7beb465a50debef2141c2534d558a1..e753306a31ff5d56c7b14e956beaad85c7c8c4ec 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1117,6 +1117,14 @@ describe Repository, models: true do end end + describe "#keep_around" do + it "stores a reference to the specified commit sha so it isn't garbage collected" do + repository.keep_around(sample_commit.id) + + expect(repository.kept_around?(sample_commit.id)).to be_truthy + end + end + def create_remote_branch(remote_name, branch_name, target) rugged = repository.rugged rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target)