Commit d4b49587 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into remove-wip

parents 09ff9bc7 f838dbe4
...@@ -5,6 +5,12 @@ v 8.6.0 (unreleased) ...@@ -5,6 +5,12 @@ v 8.6.0 (unreleased)
- Fix avatar stretching by providing a cropping feature (Johann Pardanaud) - Fix avatar stretching by providing a cropping feature (Johann Pardanaud)
- Easily (un)mark merge request as WIP using link - Easily (un)mark merge request as WIP using link
- Use specialized system notes when MR is (un)marked as WIP - Use specialized system notes when MR is (un)marked as WIP
- Strip leading and trailing spaces in URL validator (evuez)
- Update documentation to reflect Guest role not being enforced on internal projects
v 8.5.2
- Fix sidebar overlapping content when screen width was below 1200px
- Fix error 500 when commenting on a commit
v 8.5.1 v 8.5.1
- Fix group projects styles - Fix group projects styles
...@@ -25,9 +31,6 @@ v 8.5.1 ...@@ -25,9 +31,6 @@ v 8.5.1
- Update sentry-raven gem to 0.15.6 - Update sentry-raven gem to 0.15.6
- Add build coverage in project's builds page (Steffen Köhler) - Add build coverage in project's builds page (Steffen Köhler)
v 8.5.2
- Fix error 500 when commenting on a commit
v 8.5.0 v 8.5.0
- Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu) - Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu)
- Cache various Repository methods to improve performance (Yorick Peterse) - Cache various Repository methods to improve performance (Yorick Peterse)
......
...@@ -801,10 +801,7 @@ class Project < ActiveRecord::Base ...@@ -801,10 +801,7 @@ class Project < ActiveRecord::Base
end end
def change_head(branch) def change_head(branch)
# Cached divergent commit counts are based on repository head repository.before_change_head
repository.expire_branch_cache
repository.expire_root_ref_cache
gitlab_shell.update_repository_head(self.path_with_namespace, branch) gitlab_shell.update_repository_head(self.path_with_namespace, branch)
reload_default_branch reload_default_branch
end end
......
...@@ -245,15 +245,6 @@ class Repository ...@@ -245,15 +245,6 @@ class Repository
expire_emptiness_caches if empty? expire_emptiness_caches if empty?
end end
# Expires _all_ caches, including those that would normally only be expired
# under specific conditions.
def expire_all_caches!
expire_cache
expire_root_ref_cache
expire_emptiness_caches
expire_has_visible_content_cache
end
def expire_branch_cache(branch_name = nil) def expire_branch_cache(branch_name = nil)
# When we push to the root branch we have to flush the cache for all other # When we push to the root branch we have to flush the cache for all other
# branches as their statistics are based on the commits relative to the # branches as their statistics are based on the commits relative to the
...@@ -307,6 +298,46 @@ class Repository ...@@ -307,6 +298,46 @@ class Repository
cache.expire(:branch_names) cache.expire(:branch_names)
end end
# Runs code just before a repository is deleted.
def before_delete
expire_cache if exists?
expire_root_ref_cache
expire_emptiness_caches
end
# Runs code just before the HEAD of a repository is changed.
def before_change_head
# Cached divergent commit counts are based on repository head
expire_branch_cache
expire_root_ref_cache
end
# Runs code before creating a new tag.
def before_create_tag
expire_cache
end
# Runs code after a repository has been forked/imported.
def after_import
expire_emptiness_caches
end
# Runs code after a new commit has been pushed.
def after_push_commit(branch_name)
expire_cache(branch_name)
end
# Runs code after a new branch has been created.
def after_create_branch
expire_has_visible_content_cache
end
# Runs code after an existing branch has been removed.
def after_remove_branch
expire_has_visible_content_cache
end
def method_missing(m, *args, &block) def method_missing(m, *args, &block)
if m == :lookup && !block_given? if m == :lookup && !block_given?
lookup_cache[m] ||= {} lookup_cache[m] ||= {}
......
...@@ -16,13 +16,13 @@ class GitPushService < BaseService ...@@ -16,13 +16,13 @@ class GitPushService < BaseService
# 5. Executes the project's services # 5. Executes the project's services
# #
def execute def execute
@project.repository.expire_cache(branch_name) @project.repository.after_push_commit(branch_name)
if push_remove_branch? if push_remove_branch?
@project.repository.expire_has_visible_content_cache @project.repository.after_remove_branch
@push_commits = [] @push_commits = []
elsif push_to_new_branch? elsif push_to_new_branch?
@project.repository.expire_has_visible_content_cache @project.repository.after_create_branch
# Re-find the pushed commits. # Re-find the pushed commits.
if is_default_branch? if is_default_branch?
......
...@@ -2,7 +2,7 @@ class GitTagPushService ...@@ -2,7 +2,7 @@ class GitTagPushService
attr_accessor :project, :user, :push_data attr_accessor :project, :user, :push_data
def execute(project, user, oldrev, newrev, ref) def execute(project, user, oldrev, newrev, ref)
project.repository.expire_cache project.repository.before_create_tag
@project, @user = project, user @project, @user = project, user
@push_data = build_push_data(oldrev, newrev, ref) @push_data = build_push_data(oldrev, newrev, ref)
......
...@@ -76,11 +76,9 @@ module Projects ...@@ -76,11 +76,9 @@ module Projects
end end
def flush_caches(project, wiki_path) def flush_caches(project, wiki_path)
project.repository.expire_all_caches! if project.repository.exists? project.repository.before_delete
wiki_repo = Repository.new(wiki_path, project) Repository.new(wiki_path, project).before_delete
wiki_repo.expire_all_caches! if wiki_repo.exists?
end end
end end
end end
...@@ -29,8 +29,11 @@ class UrlValidator < ActiveModel::EachValidator ...@@ -29,8 +29,11 @@ class UrlValidator < ActiveModel::EachValidator
end end
def valid_url?(value) def valid_url?(value)
return false if value.nil?
options = default_options.merge(self.options) options = default_options.merge(self.options)
value.strip!
value =~ /\A#{URI.regexp(options[:protocols])}\z/ value =~ /\A#{URI.regexp(options[:protocols])}\z/
end end
end end
...@@ -27,7 +27,7 @@ class RepositoryForkWorker ...@@ -27,7 +27,7 @@ class RepositoryForkWorker
return return
end end
project.repository.expire_emptiness_caches project.repository.after_import
project.import_finish project.import_finish
end end
end end
...@@ -18,7 +18,7 @@ class RepositoryImportWorker ...@@ -18,7 +18,7 @@ class RepositoryImportWorker
return return
end end
project.repository.expire_emptiness_caches project.repository.after_import
project.import_finish project.import_finish
end end
end end
...@@ -6,7 +6,7 @@ If a user is both in a project group and in the project itself, the highest perm ...@@ -6,7 +6,7 @@ If a user is both in a project group and in the project itself, the highest perm
If a user is a GitLab administrator they receive all permissions. If a user is a GitLab administrator they receive all permissions.
On public projects the Guest role is not enforced. On public and internal projects the Guest role is not enforced.
All users will be able to create issues, leave comments, and pull or download the project code. All users will be able to create issues, leave comments, and pull or download the project code.
To add or import a user, you can follow the [project users and members To add or import a user, you can follow the [project users and members
......
...@@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do ...@@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project) visit_issues(project)
filter_by_milestone(Milestone::None.title) filter_by_milestone(Milestone::None.title)
expect(page).to have_css('.title', count: 1) expect(page).to have_css('.issue .title', count: 1)
end end
scenario 'filters by a specific Milestone', js: true do scenario 'filters by a specific Milestone', js: true do
...@@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do ...@@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project) visit_issues(project)
filter_by_milestone(milestone.title) filter_by_milestone(milestone.title)
expect(page).to have_css('.title', count: 1) expect(page).to have_css('.issue .title', count: 1)
end end
def visit_issues(project) def visit_issues(project)
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
require 'spec_helper' require 'spec_helper'
describe ProjectHook, models: true do describe ProjectHook, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
end
describe '.push_hooks' do describe '.push_hooks' do
it 'should return hooks for push events only' do it 'should return hooks for push events only' do
hook = create(:project_hook, push_events: true) hook = create(:project_hook, push_events: true)
......
...@@ -18,20 +18,14 @@ ...@@ -18,20 +18,14 @@
require 'spec_helper' require 'spec_helper'
describe ProjectHook, models: true do describe WebHook, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
end
describe "Mass assignment" do
end
describe "Validations" do describe "Validations" do
it { is_expected.to validate_presence_of(:url) } it { is_expected.to validate_presence_of(:url) }
context "url format" do describe 'url' do
it { is_expected.to allow_value("http://example.com").for(:url) } it { is_expected.to allow_value("http://example.com").for(:url) }
it { is_expected.to allow_value("https://excample.com").for(:url) } it { is_expected.to allow_value("https://example.com").for(:url) }
it { is_expected.to allow_value(" https://example.com ").for(:url) }
it { is_expected.to allow_value("http://test.com/api").for(:url) } it { is_expected.to allow_value("http://test.com/api").for(:url) }
it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) } it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) }
it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) } it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) }
...@@ -39,6 +33,12 @@ describe ProjectHook, models: true do ...@@ -39,6 +33,12 @@ describe ProjectHook, models: true do
it { is_expected.not_to allow_value("example.com").for(:url) } it { is_expected.not_to allow_value("example.com").for(:url) }
it { is_expected.not_to allow_value("ftp://example.com").for(:url) } it { is_expected.not_to allow_value("ftp://example.com").for(:url) }
it { is_expected.not_to allow_value("herp-and-derp").for(:url) } it { is_expected.not_to allow_value("herp-and-derp").for(:url) }
it 'strips :url before saving it' do
hook = create(:project_hook, url: ' https://example.com ')
expect(hook.url).to eq('https://example.com')
end
end end
end end
......
...@@ -362,14 +362,14 @@ describe Repository, models: true do ...@@ -362,14 +362,14 @@ describe Repository, models: true do
repository.expire_cache('master') repository.expire_cache('master')
end end
it 'expires the emptiness cache for an empty repository' do it 'expires the emptiness caches for an empty repository' do
expect(repository).to receive(:empty?).and_return(true) expect(repository).to receive(:empty?).and_return(true)
expect(repository).to receive(:expire_emptiness_caches) expect(repository).to receive(:expire_emptiness_caches)
repository.expire_cache repository.expire_cache
end end
it 'does not expire the emptiness cache for a non-empty repository' do it 'does not expire the emptiness caches for a non-empty repository' do
expect(repository).to receive(:empty?).and_return(false) expect(repository).to receive(:empty?).and_return(false)
expect(repository).to_not receive(:expire_emptiness_caches) expect(repository).to_not receive(:expire_emptiness_caches)
...@@ -464,4 +464,108 @@ describe Repository, models: true do ...@@ -464,4 +464,108 @@ describe Repository, models: true do
expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).not_to be_present expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).not_to be_present
end end
end end
describe '#before_delete' do
describe 'when a repository does not exist' do
before do
allow(repository).to receive(:exists?).and_return(false)
end
it 'does not flush caches that depend on repository data' do
expect(repository).to_not receive(:expire_cache)
repository.before_delete
end
it 'flushes the root ref cache' do
expect(repository).to receive(:expire_root_ref_cache)
repository.before_delete
end
it 'flushes the emptiness caches' do
expect(repository).to receive(:expire_emptiness_caches)
repository.before_delete
end
end
describe 'when a repository exists' do
before do
allow(repository).to receive(:exists?).and_return(true)
end
it 'flushes the caches that depend on repository data' do
expect(repository).to receive(:expire_cache)
repository.before_delete
end
it 'flushes the root ref cache' do
expect(repository).to receive(:expire_root_ref_cache)
repository.before_delete
end
it 'flushes the emptiness caches' do
expect(repository).to receive(:expire_emptiness_caches)
repository.before_delete
end
end
end
describe '#before_change_head' do
it 'flushes the branch cache' do
expect(repository).to receive(:expire_branch_cache)
repository.before_change_head
end
it 'flushes the root ref cache' do
expect(repository).to receive(:expire_root_ref_cache)
repository.before_change_head
end
end
describe '#before_create_tag' do
it 'flushes the cache' do
expect(repository).to receive(:expire_cache)
repository.before_create_tag
end
end
describe '#after_import' do
it 'flushes the emptiness cachess' do
expect(repository).to receive(:expire_emptiness_caches)
repository.after_import
end
end
describe '#after_push_commit' do
it 'flushes the cache' do
expect(repository).to receive(:expire_cache).with('master')
repository.after_push_commit('master')
end
end
describe '#after_create_branch' do
it 'flushes the visible content cache' do
expect(repository).to receive(:expire_has_visible_content_cache)
repository.after_create_branch
end
end
describe '#after_remove_branch' do
it 'flushes the visible content cache' do
expect(repository).to receive(:expire_has_visible_content_cache)
repository.after_remove_branch
end
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment