Commit c764980f authored by John Jarvis's avatar John Jarvis
Browse files

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 @@
.merge-request-tabs-holder {
top: $header-height;
z-index: 300;
z-index: 250;
background-color: $white-light;
border-bottom: 1px solid $border-color;
......
......@@ -4,7 +4,7 @@ class BroadcastMessage < ActiveRecord::Base
include CacheMarkdownField
include Sortable
cache_markdown_field :message, pipeline: :broadcast_message
cache_markdown_field :message, pipeline: :broadcast_message, whitelisted: true
validates :message, presence: true
validates :starts_at, presence: true
......
......@@ -7,6 +7,7 @@
# cache_markdown_field :foo
# cache_markdown_field :bar
# cache_markdown_field :baz, pipeline: :single_line
# cache_markdown_field :baz, whitelisted: true
#
# Corresponding foo_html, bar_html and baz_html fields should exist.
module CacheMarkdownField
......@@ -37,7 +38,15 @@ def html_field(markdown_field)
end
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
......@@ -149,13 +158,18 @@ def local_version
alias_method :attributes_before_markdown_cache, :attributes
def attributes
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')
cached_markdown_fields.html_fields.each do |field|
exclude_fields.each do |field|
attrs.delete(field)
end
if whitelisted.empty?
attrs.delete('cached_markdown_version')
end
attrs
end
......
......@@ -1378,6 +1378,7 @@ def change_head(branch)
repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}")
repository.copy_gitattributes(branch)
repository.after_change_head
ProjectCacheWorker.perform_async(self.id, [], [:commit_count])
reload_default_branch
else
errors.add(:base, "Could not change HEAD: branch '#{branch}' does not exist")
......
......@@ -57,7 +57,7 @@ class DiffFileEntity < DiffFileBaseEntity
diff_file.diff_lines_for_serializer
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?
end
......
......@@ -12,7 +12,7 @@
%p
By default, protected branches are designed to:
%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 <strong>anyone</strong> from force pushing to the branch
%li prevent <strong>anyone</strong> from deleting the branch
......
......@@ -27,6 +27,7 @@ def perform(project_id, files = [], statistics = [])
# rubocop: enable CodeReuse/ActiveRecord
def update_statistics(project, statistics = [])
return if Gitlab::Database.read_only?
return unless try_obtain_lease_for(project.id, :update_statistics)
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.
By default, a protected branch does four simple things:
- 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 **anyone** from force pushing to the branch
- it prevents **anyone** from deleting the branch
......
......@@ -59,6 +59,8 @@ def protected_branch_checks
def protected_branch_creation_checks
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)
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:create_protected_branch]
end
......
......@@ -158,7 +158,10 @@ def blob
new_blob || old_blob
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
def diff_lines
......@@ -314,19 +317,21 @@ def rendered_as_text?(ignore_errors: true)
# This adds the bottom match line to the array if needed. It contains
# the data to load more context lines.
def diff_lines_for_serializer
lines = highlighted_diff_lines
strong_memoize(:diff_lines_for_serializer) do
lines = highlighted_diff_lines
return if lines.empty?
return if blob.nil?
next if lines.empty?
next if blob.nil?
last_line = lines.last
last_line = lines.last
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)
lines.push(match_line)
end
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)
lines.push(match_line)
end
lines
lines
end
end
def fully_expanded?
......
......@@ -89,7 +89,7 @@ def create_source_branch_if_not_exists(merge_request)
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
Gitlab::Sentry.track_acceptable_exception(e,
extra: {
......
......@@ -5,6 +5,7 @@ module GithubImport
module Importer
class RepositoryImporter
include Gitlab::ShellAdapter
include Gitlab::Utils::StrongMemoize
attr_reader :project, :client, :wiki_formatter
......@@ -17,7 +18,7 @@ def initialize(project, client)
# Returns true if we should import the wiki for the project.
# rubocop: disable CodeReuse/ActiveRecord
def import_wiki?
client.repository(project.import_source)&.has_wiki &&
client_repository&.has_wiki &&
!project.wiki_repository_exists? &&
Gitlab::GitalyClient::RemoteService.exists?(wiki_url)
end
......@@ -52,6 +53,7 @@ def import_repository
refmap = Gitlab::GithubImport.refmap
project.repository.fetch_as_mirror(project.import_url, refmap: refmap, forced: true, remote_name: 'github')
project.change_head(default_branch) if default_branch
true
rescue Gitlab::Git::Repository::NoRepository, Gitlab::Shell::Error => e
fail_import("Failed to import the repository: #{e.message}")
......@@ -82,6 +84,18 @@ def fail_import(message)
project.import_state.mark_as_failed(message)
false
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
......
......@@ -108,64 +108,86 @@
end
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
allow(user_access)
.to receive(:can_merge_to_branch?)
.to receive(:can_push_to_branch?)
.with('feature')
.and_return(false)
.and_return(true)
end
it 'raises an error' do
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to create protected branches on this project.')
it 'does not raise an error' do
expect { subject.validate! }.not_to raise_error
end
end
context 'user is allowed to create protected branches' do
context 'user cannot push to branch' do
before do
allow(user_access)
.to receive(:can_merge_to_branch?)
.to receive(:can_push_to_branch?)
.with('feature')
.and_return(true)
allow(project.repository)
.to receive(:branch_names_contains_sha)
.with(newrev)
.and_return(['branch'])
.and_return(false)
end
context "newrev isn't in any protected branches" do
context 'user cannot merge to branch' do
before do
allow(ProtectedBranch)
.to receive(:any_protected?)
.with(project, ['branch'])
allow(user_access)
.to receive(:can_merge_to_branch?)
.with('feature')
.and_return(false)
end
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
context 'newrev is included in a protected branch' do
context 'user can merge to branch' do
before do
allow(ProtectedBranch)
.to receive(:any_protected?)
.with(project, ['branch'])
allow(user_access)
.to receive(:can_merge_to_branch?)
.with('feature')
.and_return(true)
allow(project.repository)
.to receive(:branch_names_contains_sha)
.with(newrev)
.and_return(['branch'])
end
context 'via web interface' do
let(:protocol) { 'web' }
context "newrev isn't in any protected branches" do
before do
allow(ProtectedBranch)
.to receive(:any_protected?)
.with(project, ['branch'])
.and_return(false)
end
it 'allows branch creation' do
expect { subject.validate! }.not_to raise_error
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.')
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.')
context 'newrev is included in a protected branch' do
before do
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
......
......@@ -72,6 +72,13 @@ def delete_file(file_name)
expect(diff_file.diff_lines_for_serializer.last.type).to eq('match')
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
let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') }
let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') }
......
......@@ -273,10 +273,10 @@
mr.state = 'opened'
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
# repository.
allow(project.repository).to receive(:add_branch).with(project.owner, anything, anything).and_call_original
# repository. The project owner may also be a group.
allow(project.repository).to receive(:add_branch).with(project.creator, anything, anything).and_call_original
importer.insert_git_data(mr, exists)
......
......@@ -179,6 +179,17 @@
describe '#import_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)
.to receive(:ensure_repository)
......
......@@ -146,6 +146,18 @@
expect(cache.read(key, BroadcastMessage)).to be_nil
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
context 'when the cached value is an array' do
......@@ -327,7 +339,9 @@
.with(expanded_key)
.and_return('{')
expect(cache.read(key, BroadcastMessage)).to be_nil
result = cache.fetch(key, as: BroadcastMessage) { 'block result' }
expect(result).to eq 'block result'
end
it 'gracefully handles an empty hash' do
......@@ -335,7 +349,7 @@
.with(expanded_key)
.and_return('{}')
expect(cache.read(key, BroadcastMessage)).to be_a(BroadcastMessage)
expect(cache.fetch(key, as: BroadcastMessage)).to be_a(BroadcastMessage)
end
it 'gracefully handles unknown attributes' do
......@@ -343,17 +357,19 @@
.with(expanded_key)
.and_return(broadcast_message.attributes.merge(unknown_attribute: 1).to_json)
expect(cache.read(key, BroadcastMessage)).to be_nil
result = cache.fetch(key, as: BroadcastMessage) { 'block result' }
expect(result).to eq 'block result'
end
it 'gracefully handles excluded fields from attributes during serialization' do
backend.write(expanded_key, broadcast_message.to_json)
allow(backend).to receive(:read)
.with(expanded_key)
.and_return(broadcast_message.attributes.except("message_html").to_json)
result = cache.fetch(key, as: BroadcastMessage) { 'block result' }
excluded_fields = BroadcastMessage.cached_markdown_fields.html_fields
(excluded_fields + ['cached_markdown_version']).each do |field|
BroadcastMessage.cached_markdown_fields.html_fields.each do |field|
expect(result.public_send(field)).to be_nil
end
end
......
......@@ -95,6 +95,12 @@
end
end
describe '#attributes' do
it 'includes message_html field' do
expect(subject.attributes.keys).to include("cached_markdown_version", "message_html")
end
end
describe '#active?' do
it 'is truthy when started and not ended' do
message = build(:broadcast_message)
......
......@@ -23,6 +23,7 @@ def attributes
include CacheMarkdownField
cache_markdown_field :foo
cache_markdown_field :baz, pipeline: :single_line
cache_markdown_field :zoo, whitelisted: true
def self.add_attr(name)
self.attribute_names += [name]
......@@ -35,7 +36,7 @@ def self.add_attr(name)
add_attr :cached_markdown_version
[:foo, :foo_html, :bar, :baz, :baz_html].each do |name|
[:foo, :foo_html, :bar, :baz, :baz_html, :zoo, :zoo_html].each do |name|
add_attr(name)
end
......@@ -84,8 +85,8 @@ def thing_subclass(new_attr)
end
describe '.attributes' do
it 'excludes cache attributes' do
expect(thing.attributes.keys.sort).to eq(%w[bar baz foo])
it 'excludes cache attributes that is blacklisted by default' do
expect(thing.attributes.keys.sort).to eq(%w[bar baz cached_markdown_version foo zoo zoo_html])
end
end
......@@ -297,7 +298,12 @@ def thing_subclass(new_attr)
it 'saves the changes using #update_columns' do
expect(thing).to receive(:persisted?).and_return(true)
expect(thing).to receive(:update_columns)
.with("foo_html" => updated_html, "baz_html" => "", "cached_markdown_version" => cache_version)
.with(
"foo_html" => updated_html,
"baz_html" => "",
"zoo_html" => "",
"cached_markdown_version" => cache_version
)
thing.refresh_markdown_cache!
end
......
......@@ -2388,6 +2388,12 @@
project.change_head(project.default_branch)
end
it 'updates commit count' do
expect(ProjectCacheWorker).to receive(:perform_async).with(project.id, [], [:commit_count])
project.change_head(project.default_branch)
end
it 'copies the gitattributes' do
expect(project.repository).to receive(:copy_gitattributes).with(project.default_branch)
project.change_head(project.default_branch)
......
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