Commit c764980f authored by John Jarvis's avatar John Jarvis

Merge branch '11-9-stable-patch-1' into '11-9-stable'

Prepare 11.9.1 release

See merge request gitlab-org/gitlab-ce!26538
parents a47124c7 7a83fbef
...@@ -806,7 +806,7 @@ ...@@ -806,7 +806,7 @@
.merge-request-tabs-holder { .merge-request-tabs-holder {
top: $header-height; top: $header-height;
z-index: 300; z-index: 250;
background-color: $white-light; background-color: $white-light;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
......
...@@ -4,7 +4,7 @@ class BroadcastMessage < ActiveRecord::Base ...@@ -4,7 +4,7 @@ class BroadcastMessage < ActiveRecord::Base
include CacheMarkdownField include CacheMarkdownField
include Sortable include Sortable
cache_markdown_field :message, pipeline: :broadcast_message cache_markdown_field :message, pipeline: :broadcast_message, whitelisted: true
validates :message, presence: true validates :message, presence: true
validates :starts_at, presence: true validates :starts_at, presence: true
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
# cache_markdown_field :foo # cache_markdown_field :foo
# cache_markdown_field :bar # cache_markdown_field :bar
# cache_markdown_field :baz, pipeline: :single_line # cache_markdown_field :baz, pipeline: :single_line
# cache_markdown_field :baz, whitelisted: true
# #
# Corresponding foo_html, bar_html and baz_html fields should exist. # Corresponding foo_html, bar_html and baz_html fields should exist.
module CacheMarkdownField module CacheMarkdownField
...@@ -37,7 +38,15 @@ def html_field(markdown_field) ...@@ -37,7 +38,15 @@ def html_field(markdown_field)
end end
def html_fields def html_fields
markdown_fields.map {|field| html_field(field) } markdown_fields.map { |field| html_field(field) }
end
def html_fields_whitelisted
markdown_fields.each_with_object([]) do |field, fields|
if @data[field].fetch(:whitelisted, false)
fields << html_field(field)
end
end
end end
end end
...@@ -149,13 +158,18 @@ def local_version ...@@ -149,13 +158,18 @@ def local_version
alias_method :attributes_before_markdown_cache, :attributes alias_method :attributes_before_markdown_cache, :attributes
def attributes def attributes
attrs = attributes_before_markdown_cache attrs = attributes_before_markdown_cache
html_fields = cached_markdown_fields.html_fields
whitelisted = cached_markdown_fields.html_fields_whitelisted
exclude_fields = html_fields - whitelisted
attrs.delete('cached_markdown_version') exclude_fields.each do |field|
cached_markdown_fields.html_fields.each do |field|
attrs.delete(field) attrs.delete(field)
end end
if whitelisted.empty?
attrs.delete('cached_markdown_version')
end
attrs attrs
end end
......
...@@ -1378,6 +1378,7 @@ def change_head(branch) ...@@ -1378,6 +1378,7 @@ def change_head(branch)
repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}") repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}")
repository.copy_gitattributes(branch) repository.copy_gitattributes(branch)
repository.after_change_head repository.after_change_head
ProjectCacheWorker.perform_async(self.id, [], [:commit_count])
reload_default_branch reload_default_branch
else else
errors.add(:base, "Could not change HEAD: branch '#{branch}' does not exist") errors.add(:base, "Could not change HEAD: branch '#{branch}' does not exist")
......
...@@ -57,7 +57,7 @@ class DiffFileEntity < DiffFileBaseEntity ...@@ -57,7 +57,7 @@ class DiffFileEntity < DiffFileBaseEntity
diff_file.diff_lines_for_serializer diff_file.diff_lines_for_serializer
end end
expose :is_fully_expanded, if: -> (diff_file, _) { Feature.enabled?(:expand_diff_full_file) && diff_file.text? } do |diff_file| expose :is_fully_expanded, if: -> (diff_file, _) { Feature.enabled?(:expand_diff_full_file, default_enabled: true) && diff_file.text? } do |diff_file|
diff_file.fully_expanded? diff_file.fully_expanded?
end end
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
%p %p
By default, protected branches are designed to: By default, protected branches are designed to:
%ul %ul
%li prevent their creation, if not already created, from everybody except users who are allowed to merge %li prevent their creation, if not already created, from everybody except Maintainers
%li prevent pushes from everybody except Maintainers %li prevent pushes from everybody except Maintainers
%li prevent <strong>anyone</strong> from force pushing to the branch %li prevent <strong>anyone</strong> from force pushing to the branch
%li prevent <strong>anyone</strong> from deleting the branch %li prevent <strong>anyone</strong> from deleting the branch
......
...@@ -27,6 +27,7 @@ def perform(project_id, files = [], statistics = []) ...@@ -27,6 +27,7 @@ def perform(project_id, files = [], statistics = [])
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def update_statistics(project, statistics = []) def update_statistics(project, statistics = [])
return if Gitlab::Database.read_only?
return unless try_obtain_lease_for(project.id, :update_statistics) return unless try_obtain_lease_for(project.id, :update_statistics)
Rails.logger.info("Updating statistics for project #{project.id}") Rails.logger.info("Updating statistics for project #{project.id}")
......
---
title: Fix issue that caused the "Show all activity" button to appear on top of the
mini pipeline status dropdown on the merge request page
merge_request: 26274
author:
type: fixed
---
title: Fix duplicated bottom match line on merge request parallel diff view
merge_request: 26402
author:
type: fixed
---
title: Allow users who can push to protected branches to create protected branches
via CLI
merge_request: 26413
author:
type: fixed
---
title: Add missing .gitlab-ci.yml to Android template
merge_request: 26415
author:
type: fixed
---
title: Upgrade to Gitaly v1.27.1
merge_request: 26533
author:
type: changed
---
title: Refresh commit count after repository head changes
merge_request: 26473
author:
type: fixed
---
title: Set proper default-branch for repository on GitHub Import
merge_request: 26476
author:
type: fixed
---
title: 'GitHub importer: Use the project creator to create branches from forks'
merge_request: 26510
author:
type: fixed
...@@ -10,7 +10,7 @@ created protected branches. ...@@ -10,7 +10,7 @@ created protected branches.
By default, a protected branch does four simple things: By default, a protected branch does four simple things:
- it prevents its creation, if not already created, from everybody except users - it prevents its creation, if not already created, from everybody except users
who are allowed to merge with Maintainer permission
- it prevents pushes from everybody except users with Maintainer permission - it prevents pushes from everybody except users with Maintainer permission
- it prevents **anyone** from force pushing to the branch - it prevents **anyone** from force pushing to the branch
- it prevents **anyone** from deleting the branch - it prevents **anyone** from deleting the branch
......
...@@ -59,6 +59,8 @@ def protected_branch_checks ...@@ -59,6 +59,8 @@ def protected_branch_checks
def protected_branch_creation_checks def protected_branch_creation_checks
logger.log_timed(LOG_MESSAGES[:protected_branch_creation_checks]) do logger.log_timed(LOG_MESSAGES[:protected_branch_creation_checks]) do
break if user_access.can_push_to_branch?(branch_name)
unless user_access.can_merge_to_branch?(branch_name) unless user_access.can_merge_to_branch?(branch_name)
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:create_protected_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:create_protected_branch]
end end
......
...@@ -158,7 +158,10 @@ def blob ...@@ -158,7 +158,10 @@ def blob
new_blob || old_blob new_blob || old_blob
end end
attr_writer :highlighted_diff_lines def highlighted_diff_lines=(value)
clear_memoization(:diff_lines_for_serializer)
@highlighted_diff_lines = value
end
# Array of Gitlab::Diff::Line objects # Array of Gitlab::Diff::Line objects
def diff_lines def diff_lines
...@@ -314,19 +317,21 @@ def rendered_as_text?(ignore_errors: true) ...@@ -314,19 +317,21 @@ def rendered_as_text?(ignore_errors: true)
# This adds the bottom match line to the array if needed. It contains # This adds the bottom match line to the array if needed. It contains
# the data to load more context lines. # the data to load more context lines.
def diff_lines_for_serializer def diff_lines_for_serializer
lines = highlighted_diff_lines strong_memoize(:diff_lines_for_serializer) do
lines = highlighted_diff_lines
return if lines.empty? next if lines.empty?
return if blob.nil? next if blob.nil?
last_line = lines.last last_line = lines.last
if last_line.new_pos < total_blob_lines(blob) && !deleted_file? if last_line.new_pos < total_blob_lines(blob) && !deleted_file?
match_line = Gitlab::Diff::Line.new("", 'match', nil, last_line.old_pos, last_line.new_pos) match_line = Gitlab::Diff::Line.new("", 'match', nil, last_line.old_pos, last_line.new_pos)
lines.push(match_line) lines.push(match_line)
end end
lines lines
end
end end
def fully_expanded? def fully_expanded?
......
...@@ -89,7 +89,7 @@ def create_source_branch_if_not_exists(merge_request) ...@@ -89,7 +89,7 @@ def create_source_branch_if_not_exists(merge_request)
return if project.repository.branch_exists?(source_branch) return if project.repository.branch_exists?(source_branch)
project.repository.add_branch(project.owner, source_branch, pull_request.source_branch_sha) project.repository.add_branch(project.creator, source_branch, pull_request.source_branch_sha)
rescue Gitlab::Git::CommandError => e rescue Gitlab::Git::CommandError => e
Gitlab::Sentry.track_acceptable_exception(e, Gitlab::Sentry.track_acceptable_exception(e,
extra: { extra: {
......
...@@ -5,6 +5,7 @@ module GithubImport ...@@ -5,6 +5,7 @@ module GithubImport
module Importer module Importer
class RepositoryImporter class RepositoryImporter
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Gitlab::Utils::StrongMemoize
attr_reader :project, :client, :wiki_formatter attr_reader :project, :client, :wiki_formatter
...@@ -17,7 +18,7 @@ def initialize(project, client) ...@@ -17,7 +18,7 @@ def initialize(project, client)
# Returns true if we should import the wiki for the project. # Returns true if we should import the wiki for the project.
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def import_wiki? def import_wiki?
client.repository(project.import_source)&.has_wiki && client_repository&.has_wiki &&
!project.wiki_repository_exists? && !project.wiki_repository_exists? &&
Gitlab::GitalyClient::RemoteService.exists?(wiki_url) Gitlab::GitalyClient::RemoteService.exists?(wiki_url)
end end
...@@ -52,6 +53,7 @@ def import_repository ...@@ -52,6 +53,7 @@ def import_repository
refmap = Gitlab::GithubImport.refmap refmap = Gitlab::GithubImport.refmap
project.repository.fetch_as_mirror(project.import_url, refmap: refmap, forced: true, remote_name: 'github') project.repository.fetch_as_mirror(project.import_url, refmap: refmap, forced: true, remote_name: 'github')
project.change_head(default_branch) if default_branch
true true
rescue Gitlab::Git::Repository::NoRepository, Gitlab::Shell::Error => e rescue Gitlab::Git::Repository::NoRepository, Gitlab::Shell::Error => e
fail_import("Failed to import the repository: #{e.message}") fail_import("Failed to import the repository: #{e.message}")
...@@ -82,6 +84,18 @@ def fail_import(message) ...@@ -82,6 +84,18 @@ def fail_import(message)
project.import_state.mark_as_failed(message) project.import_state.mark_as_failed(message)
false false
end end
private
def default_branch
client_repository&.default_branch
end
def client_repository
strong_memoize(:client_repository) do
client.repository(project.import_source)
end
end
end end
end end
end end
......
...@@ -108,64 +108,86 @@ ...@@ -108,64 +108,86 @@
end end
context 'protected branch creation feature is enabled' do context 'protected branch creation feature is enabled' do
context 'user is not allowed to create protected branches' do context 'user can push to branch' do
before do before do
allow(user_access) allow(user_access)
.to receive(:can_merge_to_branch?) .to receive(:can_push_to_branch?)
.with('feature') .with('feature')
.and_return(false) .and_return(true)
end end
it 'raises an error' do it 'does not raise an error' do
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to create protected branches on this project.') expect { subject.validate! }.not_to raise_error
end end
end end
context 'user is allowed to create protected branches' do context 'user cannot push to branch' do
before do before do
allow(user_access) allow(user_access)
.to receive(:can_merge_to_branch?) .to receive(:can_push_to_branch?)
.with('feature') .with('feature')
.and_return(true) .and_return(false)
allow(project.repository)
.to receive(:branch_names_contains_sha)
.with(newrev)
.and_return(['branch'])
end end
context "newrev isn't in any protected branches" do context 'user cannot merge to branch' do
before do before do
allow(ProtectedBranch) allow(user_access)
.to receive(:any_protected?) .to receive(:can_merge_to_branch?)
.with(project, ['branch']) .with('feature')
.and_return(false) .and_return(false)
end end
it 'raises an error' do it 'raises an error' do
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only use an existing protected branch ref as the basis of a new protected branch.') expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to create protected branches on this project.')
end end
end end
context 'newrev is included in a protected branch' do context 'user can merge to branch' do
before do before do
allow(ProtectedBranch) allow(user_access)
.to receive(:any_protected?) .to receive(:can_merge_to_branch?)
.with(project, ['branch']) .with('feature')
.and_return(true) .and_return(true)
allow(project.repository)
.to receive(:branch_names_contains_sha)
.with(newrev)
.and_return(['branch'])
end end
context 'via web interface' do context "newrev isn't in any protected branches" do
let(:protocol) { 'web' } before do
allow(ProtectedBranch)
.to receive(:any_protected?)
.with(project, ['branch'])
.and_return(false)
end
it 'allows branch creation' do it 'raises an error' do
expect { subject.validate! }.not_to raise_error expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only use an existing protected branch ref as the basis of a new protected branch.')
end end
end end
context 'via SSH' do context 'newrev is included in a protected branch' do
it 'raises an error' do before do
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only create protected branches using the web interface and API.') allow(ProtectedBranch)
.to receive(:any_protected?)
.with(project, ['branch'])
.and_return(true)
end
context 'via web interface' do
let(:protocol) { 'web' }
it 'allows branch creation' do
expect { subject.validate! }.not_to raise_error
end
end
context 'via SSH' do
it 'raises an error' do
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only create protected branches using the web interface and API.')
end
end end
end end
end end
......
...@@ -72,6 +72,13 @@ def delete_file(file_name) ...@@ -72,6 +72,13 @@ def delete_file(file_name)
expect(diff_file.diff_lines_for_serializer.last.type).to eq('match') expect(diff_file.diff_lines_for_serializer.last.type).to eq('match')
end end
context 'when called multiple times' do
it 'only adds bottom match line once' do
expect(diff_file.diff_lines_for_serializer.size).to eq(31)
expect(diff_file.diff_lines_for_serializer.size).to eq(31)
end
end
context 'when deleted' do context 'when deleted' do
let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') } let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') }
let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') } let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') }
......
...@@ -273,10 +273,10 @@ ...@@ -273,10 +273,10 @@
mr.state = 'opened' mr.state = 'opened'
mr.save mr.save
# Ensure the project owner is creating the branches because the # Ensure the project creator is creating the branches because the
# merge request author may not have access to push to this # merge request author may not have access to push to this
# repository. # repository. The project owner may also be a group.
allow(project.repository).to receive(:add_branch).with(project.owner, anything, anything).and_call_original allow(project.repository).to receive(:add_branch).with(project.creator, anything, anything).and_call_original
importer.insert_git_data(mr, exists) importer.insert_git_data(mr, exists)
......
...@@ -179,6 +179,17 @@ ...@@ -179,6 +179,17 @@
describe '#import_repository' do describe '#import_repository' do
it 'imports the repository' do it 'imports the repository' do
repo = double(:repo, default_branch: 'develop')
expect(client)
.to receive(:repository)
.with('foo/bar')
.and_return(repo)
expect(project)
.to receive(:change_head)
.with('develop')
expect(project) expect(project)
.to receive(:ensure_repository) .to receive(:ensure_repository)
......
...@@ -146,6 +146,18 @@ ...@@ -146,6 +146,18 @@
expect(cache.read(key, BroadcastMessage)).to be_nil expect(cache.read(key, BroadcastMessage)).to be_nil
end end
it 'gracefully handles excluded fields from attributes during serialization' do
allow(backend).to receive(:read)
.with(expanded_key)
.and_return(broadcast_message.attributes.except("message_html").to_json)
result = cache.read(key, BroadcastMessage)
BroadcastMessage.cached_markdown_fields.html_fields.each do |field|
expect(result.public_send(field)).to be_nil
end
end
end