Commit 23e8629e authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee

parents 9293d4a8 610a3d34
...@@ -34,17 +34,17 @@ When removing columns, tables, indexes or other structures: ...@@ -34,17 +34,17 @@ When removing columns, tables, indexes or other structures:
## General checklist ## General checklist
- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) added, if necessary - [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) added, if necessary
- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/doc_styleguide.html) - [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/index.html#contributing-to-docs)
- [ ] API support added - [ ] [API support added](https://docs.gitlab.com/ee/development/api_styleguide.html)
- [ ] Tests added for this feature/bug - [ ] [Tests added for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html)
- Conform by the [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html) - Conforms to the [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)
- [ ] Has been reviewed by a Backend maintainer - [ ] Has been reviewed by a Backend [maintainer](https://about.gitlab.com/handbook/engineering/#maintainer)
- [ ] Has been reviewed by a Database specialist - [ ] Has been reviewed by a Database [specialist](https://about.gitlab.com/team/structure/#specialist)
- [ ] Conform by the [merge request performance guides](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html) - [ ] Conforms to the [merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)
- [ ] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/CONTRIBUTING.md#style-guides) - [ ] Conforms to the [style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/CONTRIBUTING.md#style-guides)
- [ ] If you have multiple commits, please combine them into a few logically organized commits by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits) - [ ] If you have multiple commits, please combine them into a few logically organized commits by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
- [ ] Internationalization required/considered - [ ] [Internationalization required/considered](https://docs.gitlab.com/ee/development/i18n/index.html)
- [ ] If paid feature, have we considered GitLab.com plan and how it works for groups and is there a design for promoting it to users who aren't on the correct plan - [ ] For a paid feature, have we considered GitLab.com plans, how it works for groups, and is there a design for promoting it to users who aren't on the correct plan?
- [ ] End-to-end tests pass (`package-and-qa` manual pipeline job) - [ ] [End-to-end tests](https://docs.gitlab.com/ee/development/testing_guide/end_to_end_tests.html#testing-code-in-merge-requests) pass (`package-and-qa` manual pipeline job)
/label ~database /label ~database
<!--See the general Documentation guidelines https://docs.gitlab.com/ce/development/writing_documentation.html --> <!--See the general Documentation guidelines https://docs.gitlab.com/ee/development/documentation/index.html -->
## What does this MR do? ## What does this MR do?
...@@ -13,17 +13,17 @@ Closes ...@@ -13,17 +13,17 @@ Closes
## Moving docs to a new location? ## Moving docs to a new location?
Read the guidelines: Read the guidelines:
https://docs.gitlab.com/ce/development/writing_documentation.html#changing-document-location https://docs.gitlab.com/ee/development/documentation/#changing-document-location
- [ ] Make sure the old link is not removed and has its contents replaced with - [ ] Make sure the old link is not removed and has its contents replaced with
a link to the new location. a link to the new location.
- [ ] Make sure internal links pointing to the document in question are not broken. - [ ] Make sure internal links pointing to the document in question are not broken.
- [ ] Search and replace any links referring to old docs in GitLab Rails app, - [ ] Search and replace any links referring to the old docs in the GitLab Rails app,
specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories. specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories.
- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/writing_documentation.html#redirections-for-pages-with-disqus-comments) - [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ee/development/documentation/index.html#redirections-for-pages-with-disqus-comments)
to the new document if there are any Disqus comments on the old document thread. to the new document if there are any Disqus comments on the old document thread.
- [ ] If working on CE and the `ee-compat-check` jobs fails, submit an MR to EE - [ ] If working on CE and the `ee-compat-check` jobs fails, [submit an MR to EE
with the changes as well (https://docs.gitlab.com/ce/development/writing_documentation.html#cherry-picking-from-ce-to-ee). with the changes](https://docs.gitlab.com/ee/development/documentation/index.html#cherry-picking-from-ce-to-ee) as well.
- [ ] Ping one of the technical writers for review. - [ ] Ping one of the technical writers for review.
/label ~Documentation /label ~Documentation
...@@ -302,7 +302,6 @@ $system-footer-height: $system-header-height; ...@@ -302,7 +302,6 @@ $system-footer-height: $system-header-height;
$flash-height: 52px; $flash-height: 52px;
$context-header-height: 60px; $context-header-height: 60px;
$breadcrumb-min-height: 48px; $breadcrumb-min-height: 48px;
$gcp-signup-offer-icon-max-width: 125px;
$issue-box-upcoming-bg: #8f8f8f; $issue-box-upcoming-bg: #8f8f8f;
$pages-group-name-color: #4c4e54; $pages-group-name-color: #4c4e54;
......
...@@ -32,49 +32,23 @@ ...@@ -32,49 +32,23 @@
} }
.gcp-signup-offer { .gcp-signup-offer {
background-color: $blue-50; border-left-color: $blue-500;
border: 1px solid $blue-300;
border-radius: $border-radius-default;
// TODO: To be superceded by cssLab svg {
&.alert { fill: $blue-500;
padding: 24px 16px; vertical-align: middle;
&-dismissable {
padding-right: 32px;
.close {
top: -8px;
right: -16px;
color: $blue-500;
opacity: 1;
}
}
}
.gcp-logo {
margin-bottom: $gl-padding;
text-align: center;
}
img {
max-width: $gcp-signup-offer-icon-max-width;
} }
a:not(.btn) { .gcp-signup-offer--content {
color: $gl-link-color; display: flex;
font-weight: normal;
text-decoration: none;
}
@include media-breakpoint-up(sm) { h4 {
> div { font-size: 16px;
display: flex; line-height: 24px;
align-items: center;
} }
.gcp-logo { .gcp-signup-offer--icon {
margin: 0; align-self: flex-start;
} }
} }
} }
...@@ -116,7 +116,12 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -116,7 +116,12 @@ class Projects::WikisController < Projects::ApplicationController
# Call #wiki to make sure the Wiki Repo is initialized # Call #wiki to make sure the Wiki Repo is initialized
@project_wiki.wiki @project_wiki.wiki
@sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.pages(limit: 15))
@sidebar_page = @project_wiki.find_sidebar(params[:version_id])
unless @sidebar_page # Fallback to default sidebar
@sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.pages(limit: 15))
end
rescue ProjectWiki::CouldNotCreateWikiError rescue ProjectWiki::CouldNotCreateWikiError
flash[:notice] = "Could not create Wiki Repository at this time. Please try again later." flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
redirect_to project_path(@project) redirect_to project_path(@project)
......
...@@ -415,20 +415,6 @@ module ProjectsHelper ...@@ -415,20 +415,6 @@ module ProjectsHelper
@ref || @repository.try(:root_ref) @ref || @repository.try(:root_ref)
end end
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1235
def sanitize_repo_path(project, message)
return '' unless message.present?
exports_path = File.join(Settings.shared['path'], 'tmp/project_exports')
filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]")
disk_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
end
filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]")
end
def project_child_container_class(view_path) def project_child_container_class(view_path)
view_path == "projects/issues/issues" ? "prepend-top-default" : "project-show-#{view_path}" view_path == "projects/issues/issues" ? "prepend-top-default" : "project-show-#{view_path}"
end end
......
...@@ -2185,10 +2185,13 @@ class Project < ActiveRecord::Base ...@@ -2185,10 +2185,13 @@ class Project < ActiveRecord::Base
merge_requests = source_of_merge_requests.opened merge_requests = source_of_merge_requests.opened
.where(allow_collaboration: true) .where(allow_collaboration: true)
if branch_name # Issue for N+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/49322
merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user) Gitlab::GitalyClient.allow_n_plus_1_calls do
else if branch_name
merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) } merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user)
else
merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) }
end
end end
end end
......
# frozen_string_literal: true
class ProjectWiki class ProjectWiki
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Storage::LegacyProjectWiki include Storage::LegacyProjectWiki
...@@ -12,6 +14,7 @@ class ProjectWiki ...@@ -12,6 +14,7 @@ class ProjectWiki
}.freeze unless defined?(MARKUPS) }.freeze unless defined?(MARKUPS)
CouldNotCreateWikiError = Class.new(StandardError) CouldNotCreateWikiError = Class.new(StandardError)
SIDEBAR = '_sidebar'
# Returns a string describing what went wrong after # Returns a string describing what went wrong after
# an operation fails. # an operation fails.
...@@ -106,6 +109,10 @@ class ProjectWiki ...@@ -106,6 +109,10 @@ class ProjectWiki
end end
end end
def find_sidebar(version = nil)
find_page(SIDEBAR, version)
end
def find_file(name, version = nil) def find_file(name, version = nil)
wiki.file(name, version) wiki.file(name, version)
end end
......
- link = link_to(s_('ClusterIntegration|sign up'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer') - link = link_to(s_('ClusterIntegration|sign up'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert' } .bs-callout.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert' }
%button.close{ type: "button", data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } } &times; %button.close{ type: "button", data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } } &times;
%div .gcp-signup-offer--content
.col-sm-2.gcp-logo .gcp-signup-offer--icon.append-right-8
= image_tag 'illustrations/logos/google-cloud-platform_logo.svg' = sprite_icon("information", size: 16)
.col-sm-10 .gcp-signup-offer--copy
%h4= s_('ClusterIntegration|Redeem up to $500 in free credit for Google Cloud Platform') %h4= s_('ClusterIntegration|Did you know?')
%p= s_('ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab\'s Google Kubernetes Engine Integration.').html_safe % { sign_up_link: link } %p= s_('ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab\'s Google Kubernetes Engine Integration.').html_safe % { sign_up_link: link }
%a.btn.btn-info{ href: 'https://goo.gl/AaJzRW', target: '_blank', rel: 'noopener noreferrer' } %a.btn.btn-default{ href: 'https://goo.gl/AaJzRW', target: '_blank', rel: 'noopener noreferrer' }
Apply for credit Apply for credit
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
- branch_label = s_('ChangeTypeActionLabel|Pick into branch') - branch_label = s_('ChangeTypeActionLabel|Pick into branch')
- title = commit.merged_merge_request(current_user) ? _('Cherry-pick this merge request') : _('Cherry-pick this commit') - title = commit.merged_merge_request(current_user) ? _('Cherry-pick this merge request') : _('Cherry-pick this commit')
.modal{ id: "modal-#{type}-commit" } .modal{ id: "modal-#{type}-commit", tabindex: -1 }
.modal-dialog .modal-dialog
.modal-content .modal-content
.modal-header .modal-header
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
.card-body .card-body
%pre %pre
:preserve :preserve
#{h(sanitize_repo_path(@project, @project.import_error))} #{h(@project.import_error)}
= form_for @project, url: project_import_path(@project), method: :post do |f| = form_for @project, url: project_import_path(@project), method: :post do |f|
= render "shared/import_form", f: f = render "shared/import_form", f: f
......
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
.blocks-container .blocks-container
.block.block-first .block.block-first
%ul.wiki-pages - if @sidebar_page
= render @sidebar_wiki_entries, context: 'sidebar' = render_wiki_content(@sidebar_page)
- else
%ul.wiki-pages
= render @sidebar_wiki_entries, context: 'sidebar'
.block .block
= link_to project_wikis_pages_path(@project), class: 'btn btn-block' do = link_to project_wikis_pages_path(@project), class: 'btn btn-block' do
= s_("Wiki|More Pages") = s_("Wiki|More Pages")
......
---
title: "Custom Wiki Sidebar Support Issue 14995"
merge_request:
author: Josh Sooter
type: added
---
title: Redesign GCP offer banner
merge_request:
author:
type: changed
---
title: Close revert and cherry pick modal on escape keypress
merge_request: 20341
author: George Tsiolis
type: changed
---
title: Add emails delivery Prometheus metrics
merge_request: 20638
author:
type: added
unless Gitlab.config.gitlab.email_enabled
ActionMailer::Base.register_interceptor(::Gitlab::Email::Hook::DisableEmailInterceptor)
ActionMailer::Base.logger = nil
end
ActionMailer::Base.register_interceptors(
::Gitlab::Email::Hook::AdditionalHeadersInterceptor,
::Gitlab::Email::Hook::EmailTemplateInterceptor,
::Gitlab::Email::Hook::DeliveryMetricsObserver
)
ActionMailer::Base.register_observer(::Gitlab::Email::Hook::DeliveryMetricsObserver)
ActionMailer::Base.register_interceptor(AdditionalEmailHeadersInterceptor)
# Interceptor in lib/disable_email_interceptor.rb
unless Gitlab.config.gitlab.email_enabled
ActionMailer::Base.register_interceptor(DisableEmailInterceptor)
ActionMailer::Base.logger = nil
end
# Interceptor in lib/email_template_interceptor.rb
ActionMailer::Base.register_interceptor(EmailTemplateInterceptor)
...@@ -243,3 +243,45 @@ WHERE EXISTS ( ...@@ -243,3 +243,45 @@ WHERE EXISTS (
``` ```
[gin-index]: http://www.postgresql.org/docs/current/static/gin.html [gin-index]: http://www.postgresql.org/docs/current/static/gin.html
## `.find_or_create_by` is not atomic
The inherent pattern with methods like `.find_or_create_by` and
`.first_or_create` and others is that they are not atomic. This means,
it first runs a `SELECT`, and if there are no results an `INSERT` is
performed. With concurrent processes in mind, there is a race condition
which may lead to trying to insert two similar records. This may not be
desired, or may cause one of the queries to fail due to a constraint
violation, for example.
Using transactions does not solve this problem.
The following pattern should be used to avoid the problem:
```ruby
Project.transaction do
begin
User.find_or_create_by(username: "foo")
rescue ActiveRecord::RecordNotUnique
retry
end
end
```
If the above block is run inside a transaction and hits the race
condition, the transaction is aborted and we cannot simply retry (any
further queries inside the aborted transaction are going to fail). We
can employ [nested transactions](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions)
here to only rollback the "inner transaction". Note that `requires_new: true` is required here.
```ruby
Project.transaction do
begin
User.transaction(requires_new: true) do
User.find_or_create_by(username: "foo")
end
rescue ActiveRecord::RecordNotUnique
retry
end
end
```
# Import multiple repositories by uploading a manifest file # Import multiple repositories by uploading a manifest file
GitLab allows you to import all the required git repositories GitLab allows you to import all the required git repositories
based a manifest file like the one used by the Android repository. based a manifest file like the one used by the [Android repository](https://android.googlesource.com/platform/manifest/+/2d6f081a3b05d8ef7a2b1b52b0d536b2b74feab4/default.xml).
This feature can be very handy when you need to import a project with many repositories like Android Open Source Project (AOSP).
>**Note:** >**Note:**
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
>**Notes:** >**Notes:**
- [Introduced][ee-1540] in [GitLab Starter 9.1][ee-9.1] for project milestones. - [Introduced][ee-1540] in [GitLab Starter 9.1][ee-9.1] for project milestones.
- [Introduced][ee-5354] in [GitLab Premium 10.8][ee-10.8] for group milestones. - [Introduced][ee-5354] in [GitLab Premium 10.8][ee-10.8] for group milestones.
- [Added][ee-6495] to [GitLab Starter 11.2][ee-11.2] for group milestones.
- Closed or reopened issues prior to GitLab 9.1 won't have a `closed_at` - Closed or reopened issues prior to GitLab 9.1 won't have a `closed_at`
value, so the burndown chart considers them as closed on the milestone value, so the burndown chart considers them as closed on the milestone
`start_date`. In that case, a warning will be displayed. `start_date`. In that case, a warning will be displayed.
......
...@@ -107,3 +107,10 @@ On the right sidebar, click on **Clone repository** and follow the on-screen ...@@ -107,3 +107,10 @@ On the right sidebar, click on **Clone repository** and follow the on-screen
instructions. instructions.
[permissions]: ../../permissions.md [permissions]: ../../permissions.md
## Customizing sidebar
By default, the wiki would render a sidebar which lists all the pages for the
wiki. You could as well provide a `_sidebar` page to replace this default
sidebar. When this customized sidebar page is provided, the default sidebar
would not be rendered, but the customized one.
...@@ -13,6 +13,7 @@ class License < ActiveRecord::Base ...@@ -13,6 +13,7 @@ class License < ActiveRecord::Base
elastic_search elastic_search
export_issues export_issues
external_files_in_gitlab_ci external_files_in_gitlab_ci
group_burndown_charts
group_webhooks group_webhooks
issuable_default_templates issuable_default_templates
issue_board_focus_mode issue_board_focus_mode
...@@ -59,7 +60,6 @@ class License < ActiveRecord::Base ...@@ -59,7 +60,6 @@ class License < ActiveRecord::Base
commit_committer_check commit_committer_check
external_authorization_service external_authorization_service
ci_cd_projects ci_cd_projects
group_burndown_charts
system_header_footer system_header_footer
].freeze ].freeze
......
---
title: Adds a burndown chart on the group milestone page in Starter.
merge_request: 6495
author:
type: fixed
module EE
module Banzai
module Pipeline
module GfmPipeline
extend ActiveSupport::Concern
class_methods do
def reference_filters
[
::Banzai::Filter::EpicReferenceFilter,
*super
]
end
end
end
end
end
end
module EE
module Banzai
module Pipeline
module PostProcessPipeline
extend ActiveSupport::Concern
class_methods do
def internal_link_filters
[
*super,
::Banzai::Filter::CrossProjectIssuableInformationFilter
]
end
end
end
end
end
end
module EE
module Banzai
module Pipeline
module SingleLinePipeline
extend ActiveSupport::Concern
class_methods do
def reference_filters
[
::Banzai::Filter::EpicReferenceFilter,
*super
]
end
end
end
end
end
end
class AdditionalEmailHeadersInterceptor
def self.delivering_email(message)
message.header['Auto-Submitted'] ||= 'auto-generated'
message.header['X-Auto-Response-Suppress'] ||= 'All'
end
end
module Banzai module Banzai
module Pipeline module Pipeline
class GfmPipeline < BasePipeline class GfmPipeline < BasePipeline
prepend EE::Banzai::Pipeline::GfmPipeline
# These filters convert GitLab Flavored Markdown (GFM) to HTML. # These filters convert GitLab Flavored Markdown (GFM) to HTML.
# The handlers defined in app/assets/javascripts/behaviors/markdown/copy_as_gfm.js # The handlers defined in app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
# consequently convert that same HTML to GFM to be copied to the clipboard. # consequently convert that same HTML to GFM to be copied to the clipboard.
...@@ -24,7 +26,17 @@ module Banzai ...@@ -24,7 +26,17 @@ module Banzai
Filter::AutolinkFilter, Filter::AutolinkFilter,
Filter::ExternalLinkFilter, Filter::ExternalLinkFilter,
Filter::EpicReferenceFilter, *reference_filters,
Filter::TaskListFilter,
Filter::InlineDiffFilter,
Filter::SetDirectionFilter
]
end
def self.reference_filters
[
Filter::UserReferenceFilter, Filter::UserReferenceFilter,
Filter::IssueReferenceFilter, Filter::IssueReferenceFilter,
Filter::ExternalIssueReferenceFilter, Filter::ExternalIssueReferenceFilter,
...@@ -33,12 +45,7 @@ module Banzai ...@@ -33,12 +45,7 @@ module Banzai
Filter::CommitRangeReferenceFilter, Filter::CommitRangeReferenceFilter,
Filter::CommitReferenceFilter, Filter::CommitReferenceFilter,
Filter::LabelReferenceFilter, Filter::LabelReferenceFilter,
Filter::MilestoneReferenceFilter, Filter::MilestoneReferenceFilter
Filter::TaskListFilter,
Filter::InlineDiffFilter,
Filter::SetDirectionFilter
] ]
end end
......
module Banzai module Banzai
module Pipeline module Pipeline
class PostProcessPipeline < BasePipeline class PostProcessPipeline < BasePipeline
prepend EE::Banzai::Pipeline::PostProcessPipeline
def self.filters def self.filters
FilterArray[ @filters ||= FilterArray[
*internal_link_filters,
Filter::AbsoluteLinkFilter
]
end
def self.internal_link_filters
[
Filter::RedactorFilter, Filter::RedactorFilter,
Filter::RelativeLinkFilter, Filter::RelativeLinkFilter,
Filter::IssuableStateFilter, Filter::IssuableStateFilter
Filter::CrossProjectIssuableInformationFilter,
Filter::AbsoluteLinkFilter
] ]
end end
......
module Banzai module Banzai
module Pipeline module Pipeline
class SingleLinePipeline < GfmPipeline class SingleLinePipeline < GfmPipeline
prepend EE::Banzai::Pipeline::SingleLinePipeline
def self.filters def self.filters
@filters ||= FilterArray[ @filters ||= FilterArray[
Filter::HtmlEntityFilter, Filter::HtmlEntityFilter,
...@@ -10,7 +12,12 @@ module Banzai ...@@ -10,7 +12,12 @@ module Banzai
Filter::AutolinkFilter, Filter::AutolinkFilter,
Filter::ExternalLinkFilter, Filter::ExternalLinkFilter,
Filter::EpicReferenceFilter, *reference_filters
]
end
def self.reference_filters
[
Filter::UserReferenceFilter, Filter::UserReferenceFilter,
Filter::IssueReferenceFilter, Filter::IssueReferenceFilter,
Filter::ExternalIssueReferenceFilter, Filter::ExternalIssueReferenceFilter,
......
# Read about interceptors in http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails
class DisableEmailInterceptor
def self.delivering_email(message)
message.perform_deliveries = false
Rails.logger.info "Emails disabled! Interceptor prevented sending mail #{message.subject}"
end
end
# Read about interceptors in http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails
class EmailTemplateInterceptor
def self.delivering_email(message)
# Remove HTML part if HTML emails are disabled.
unless Gitlab::CurrentSettings.html_emails_enabled
message.parts.delete_if do |part|
part.content_type.start_with?('text/html')
end
end
end
end
module Gitlab
module Email
module Hook
class AdditionalHeadersInterceptor
def self.delivering_email(message)
message.header['Auto-Submitted'] ||= 'auto-generated'
message.header['X-Auto-Response-Suppress'] ||= 'All'
end
end
end
end
end
module Gitlab
module Email
module Hook
class DeliveryMetricsObserver
extend Gitlab::Utils::StrongMemoize
def self.delivering_email(_message)
delivery_attempts_counter.increment
end
def self.delivered_email(_message)
delivered_emails_counter.increment
end
def self.delivery_attempts_counter
strong_memoize(:delivery_attempts_counter) do
Gitlab::Metrics.counter(:gitlab_emails_delivery_attempts_total,
'Counter of total emails delivery attempts')
end
end
def self.delivered_emails_counter
strong_memoize(:delivered_emails_counter) do
Gitlab::Metrics.counter(:gitlab_emails_delivered_total,
'Counter of total emails delievered')
end
end
end
end
end
end
module Gitlab
module Email
module Hook
class DisableEmailInterceptor
def self.delivering_email(message)
message.perform_deliveries = false
Rails.logger.info "Emails disabled! Interceptor prevented sending mail #{message.subject}"
end
end
end
end
end
module Gitlab
module Email
module Hook
class EmailTemplateInterceptor
##
# Remove HTML part if HTML emails are disabled.
#
def self.delivering_email(message)
unless Gitlab::CurrentSettings.html_emails_enabled
message.parts.delete_if do |part|
part.content_type.start_with?('text/html')
end
end
end
end
end
end
end
...@@ -443,12 +443,8 @@ module Gitlab ...@@ -443,12 +443,8 @@ module Gitlab
# Returns the SHA of the most recent common ancestor of +from+ and +to+ # Returns the SHA of the most recent common ancestor of +from+ and +to+
def merge_base(from, to) def merge_base(from, to)
gitaly_migrate(:merge_base) do |is_enabled| wrapped_gitaly_errors do
if is_enabled gitaly_repository_client.find_merge_base(from, to)
gitaly_repository_client.find_merge_base(from, to)
else
rugged_merge_base(from, to)
end
end end
end end
...@@ -464,12 +460,8 @@ module Gitlab ...@@ -464,12 +460,8 @@ module Gitlab
return [] unless root_sha return [] unless root_sha
branches = gitaly_migrate(:merged_branch_names) do |is_enabled| branches = wrapped_gitaly_errors do
if is_enabled gitaly_merged_branch_names(branch_names, root_sha)
gitaly_merged_branch_names(branch_names, root_sha)
else
git_merged_branch_names(branch_names, root_sha)
end
end end
Set.new(branches) Set.new(branches)
...@@ -848,12 +840,8 @@ module Gitlab ...@@ -848,12 +840,8 @@ module Gitlab
def write_ref(ref_path, ref, old_ref: nil, shell: true) def write_ref(ref_path, ref, old_ref: nil, shell: true)
ref_path = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref_path}" unless ref_path.start_with?("refs/") || ref_path == "HEAD" ref_path = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref_path}" unless ref_path.start_with?("refs/") || ref_path == "HEAD"
gitaly_migrate(:write_ref) do |is_enabled| wrapped_gitaly_errors do
if is_enabled gitaly_repository_client.write_ref(ref_path, ref, old_ref, shell)
gitaly_repository_client.write_ref(ref_path, ref, old_ref, shell)
else
local_write_ref(ref_path, ref, old_ref: old_ref, shell: shell)
end
end end
end end
...@@ -1188,37 +1176,6 @@ module Gitlab ...@@ -1188,37 +1176,6 @@ module Gitlab
end end
end end
def local_write_ref(ref_path, ref, old_ref: nil, shell: true)
if shell
shell_write_ref(ref_path, ref, old_ref)
else
rugged_write_ref(ref_path, ref)
end
end
def rugged_write_config(full_path:)
rugged.config['gitlab.fullpath'] = full_path
end
def shell_write_ref(ref_path, ref, old_ref)
raise ArgumentError, "invalid ref_path #{ref_path.inspect}" if ref_path.include?(' ')
raise ArgumentError, "invalid ref #{ref.inspect}" if ref.include?("\x00")
raise ArgumentError, "invalid old_ref #{old_ref.inspect}" if !old_ref.nil? && old_ref.include?("\x00")
input = "update #{ref_path}\x00#{ref}\x00#{old_ref}\x00"
run_git!(%w[update-ref --stdin -z]) { |stdin| stdin.write(input) }
end
def rugged_write_ref(ref_path, ref)
rugged.references.create(ref_path, ref, force: true)
rescue Rugged::ReferenceError => ex
Rails.logger.error "Unable to create #{ref_path} reference for repository #{path}: #{ex}"
rescue Rugged::OSError => ex
raise unless ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/
Rails.logger.error "Unable to create #{ref_path} reference for repository #{path}: #{ex}"
end
def run_git(args, chdir: path, env: {}, nice: false, lazy_block: nil, &block) def run_git(args, chdir: path, env: {}, nice: false, lazy_block: nil, &block)
cmd = [Gitlab.config.git.bin_path, *args] cmd = [Gitlab.config.git.bin_path, *args]
cmd.unshift("nice") if nice cmd.unshift("nice") if nice
...@@ -1289,20 +1246,6 @@ module Gitlab ...@@ -1289,20 +1246,6 @@ module Gitlab
} }
end end
def git_merged_branch_names(branch_names, root_sha)
git_arguments =
%W[branch --merged #{root_sha}
--format=%(refname:short)\ %(objectname)] + branch_names
lines = run_git(git_arguments).first.lines
lines.each_with_object([]) do |line, branches|
name, sha = line.strip.split(' ', 2)
branches << name if sha != root_sha
end
end
def gitaly_merged_branch_names(branch_names, root_sha) def gitaly_merged_branch_names(branch_names, root_sha)
qualified_branch_names = branch_names.map { |b| "refs/heads/#{b}" } qualified_branch_names = branch_names.map { |b| "refs/heads/#{b}" }
...@@ -1448,12 +1391,6 @@ module Gitlab ...@@ -1448,12 +1391,6 @@ module Gitlab
raise CommandError, @gitlab_projects.output raise CommandError, @gitlab_projects.output
end end
def rugged_merge_base(from, to)
rugged.merge_base(from, to)
rescue Rugged::ReferenceError
nil
end
def rev_list_param(spec) def rev_list_param(spec)
spec == :all ? ['--all'] : spec spec == :all ? ['--all'] : spec
end end
......
...@@ -1497,6 +1497,9 @@ msgstr "" ...@@ -1497,6 +1497,9 @@ msgstr ""
msgid "ClusterIntegration|Create Kubernetes cluster" msgid "ClusterIntegration|Create Kubernetes cluster"
msgstr "" msgstr ""
msgid "ClusterIntegration|Did you know?"
msgstr ""
msgid "ClusterIntegration|Enter the details for your Kubernetes cluster" msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
msgstr "" msgstr ""
...@@ -1674,9 +1677,6 @@ msgstr "" ...@@ -1674,9 +1677,6 @@ msgstr ""
msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration." msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
msgstr "" msgstr ""
msgid "ClusterIntegration|Redeem up to $500 in free credit for Google Cloud Platform"
msgstr ""
msgid "ClusterIntegration|Remove Kubernetes cluster integration" msgid "ClusterIntegration|Remove Kubernetes cluster integration"
msgstr "" msgstr ""
......
require 'rails_helper' require 'rails_helper'
describe 'Merge request > User sees Check out branch modal', :js do describe 'Merge request > User sees check out branch modal', :js do
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator } let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
...@@ -16,7 +16,7 @@ describe 'Merge request > User sees Check out branch modal', :js do ...@@ -16,7 +16,7 @@ describe 'Merge request > User sees Check out branch modal', :js do
expect(page).to have_content('Check out, review, and merge locally') expect(page).to have_content('Check out, review, and merge locally')
end end
it 'closes the check out branch model with Escape keypress' do it 'closes the check out branch modal with escape keypress' do
find('#modal_merge_info').send_keys(:escape) find('#modal_merge_info').send_keys(:escape)
expect(page).not_to have_content('Check out, review, and merge locally') expect(page).not_to have_content('Check out, review, and merge locally')
......
...@@ -21,7 +21,7 @@ describe 'Merge request > User cherry-picks', :js do ...@@ -21,7 +21,7 @@ describe 'Merge request > User cherry-picks', :js do
end end
# Fast-forward merge, or merged before GitLab 8.5. # Fast-forward merge, or merged before GitLab 8.5.
context 'Without a merge commit' do context 'without a merge commit' do
before do before do
merge_request.merge_commit_sha = nil merge_request.merge_commit_sha = nil
merge_request.save merge_request.save
...@@ -34,7 +34,7 @@ describe 'Merge request > User cherry-picks', :js do ...@@ -34,7 +34,7 @@ describe 'Merge request > User cherry-picks', :js do
end end
end end
context 'With a merge commit' do context 'with a merge commit' do
it 'shows a Cherry-pick button' do it 'shows a Cherry-pick button' do
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
...@@ -49,5 +49,23 @@ describe 'Merge request > User cherry-picks', :js do ...@@ -49,5 +49,23 @@ describe 'Merge request > User cherry-picks', :js do
expect(page).not_to have_link 'Cherry-pick' expect(page).not_to have_link 'Cherry-pick'
end end
end end
context 'and seeing the cherry-pick modal' do
before do
visit project_merge_request_path(project, merge_request)
click_link('Cherry-pick')
end
it 'shows the cherry-pick modal' do
expect(page).to have_content('Cherry-pick this merge request')
end
it 'closes the cherry-pick modal with escape keypress' do
find('#modal-cherry-pick-commit').send_keys(:escape)
expect(page).not_to have_content('Start a new merge request with these changes')
end
end
end end
end end
...@@ -2,16 +2,22 @@ require "spec_helper" ...@@ -2,16 +2,22 @@ require "spec_helper"
describe "User creates wiki page" do describe "User creates wiki page" do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:wiki) { ProjectWiki.new(project, user) }
let(:project) { create(:project) }
before do before do
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user)
visit(project_wikis_path(project)) sign_in(user)
click_link "Create your first page"
end end
context "when wiki is empty" do context "when wiki is empty" do
before do
visit(project_wikis_path(project))
click_link "Create your first page"
end
context "in a user namespace" do context "in a user namespace" do
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
...@@ -165,7 +171,9 @@ describe "User creates wiki page" do ...@@ -165,7 +171,9 @@ describe "User creates wiki page" do
context "when wiki is not empty", :js do context "when wiki is not empty", :js do
before do before do
create(:wiki_page, wiki: create(:project, :wiki_repo, namespace: user.namespace).wiki, attrs: { title: "home", content: "Home page" }) create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'Home page' })
visit(project_wikis_path(project))
end end
context "in a user namespace" do context "in a user namespace" do
...@@ -290,4 +298,34 @@ describe "User creates wiki page" do ...@@ -290,4 +298,34 @@ describe "User creates wiki page" do
end end
end end
end end
describe 'sidebar feature' do
context 'when there are some existing pages' do
before do
create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' })
create(:wiki_page, wiki: wiki, attrs: { title: 'another', content: 'another' })
end
it 'renders a default sidebar when there is no customized sidebar' do
visit(project_wikis_path(project))
expect(page).to have_content('Another')
expect(page).to have_content('More Pages')
end
context 'when there is a customized sidebar' do
before do
create(:wiki_page, wiki: wiki, attrs: { title: '_sidebar', content: 'My customized sidebar' })
end
it 'renders my customized sidebar instead of the default one' do
visit(project_wikis_path(project))
expect(page).to have_content('My customized sidebar')
expect(page).to have_content('More Pages')
expect(page).not_to have_content('Another')
end
end
end
end
end end
require 'rails_helper'
describe 'Merge request > User sees revert modal', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
before do
sign_in(user)
visit(project_merge_request_path(project, merge_request))
click_button('Merge')
visit(merge_request_path(merge_request))
click_link('Revert')
end
it 'shows the revert modal' do
expect(page).to have_content('Revert this merge request')
end
it 'closes the revert modal with escape keypress' do
find('#modal-revert-commit').send_keys(:escape)
expect(page).not_to have_content('Revert this merge request')
end
end
...@@ -299,33 +299,6 @@ describe ProjectsHelper do ...@@ -299,33 +299,6 @@ describe ProjectsHelper do
end end
end end
describe '#sanitize_repo_path' do
let(:project) { create(:project, :repository) }
let(:storage_path) do
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages.default.legacy_disk_path
end
end
before do
allow(Settings.shared).to receive(:[]).with('path').and_return('/base/repo/export/path')
end
it 'removes the repo path' do
repo = File.join(storage_path, 'namespace/test.git')
import_error = "Could not clone #{repo}\n"
expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git')
end
it 'removes the temporary repo path used for uploads/exports' do
repo = '/base/repo/export/path/tmp/project_exports/uploads/test.tar.gz'
import_error = "Unable to decompress #{repo}\n"
expect(sanitize_repo_path(project, import_error)).to eq('Unable to decompress [REPO EXPORT PATH]/uploads/test.tar.gz')
end
end
describe '#last_push_event' do describe '#last_push_event' do
let(:user) { double(:user, fork_of: nil) } let(:user) { double(:user, fork_of: nil) }
let(:project) { double(:project, id: 1) } let(:project) { double(:project, id: 1) }
......
require 'spec_helper' require 'spec_helper'
describe AdditionalEmailHeadersInterceptor do describe Gitlab::Email::Hook::AdditionalHeadersInterceptor do
let(:mail) do let(:mail) do
ActionMailer::Base.mail(to: 'test@mail.com', from: 'info@mail.com', body: 'hello') ActionMailer::Base.mail(to: 'test@mail.com', from: 'info@mail.com', body: 'hello')
end end
......
require 'spec_helper'
describe Gitlab::Email::Hook::DeliveryMetricsObserver do
let(:email) do
ActionMailer::Base.mail(to: 'test@example.com',
from: 'info@example.com',
body: 'hello')
end
context 'when email has been delivered' do
it 'increments both email delivery metrics' do
expect(described_class.delivery_attempts_counter).to receive(:increment)
expect(described_class.delivered_emails_counter).to receive(:increment)
email.deliver_now
end
end
context 'when email has not been delivered due to an error' do
before do
allow(email.delivery_method).to receive(:deliver!)
.and_raise(StandardError, 'Some SMTP error')
end
it 'increments only delivery attempt metric' do
expect(described_class.delivery_attempts_counter)
.to receive(:increment)
expect(described_class.delivered_emails_counter)
.not_to receive(:increment)
expect { email.deliver_now }
.to raise_error(StandardError, 'Some SMTP error')
end
end
end
require 'spec_helper' require 'spec_helper'
describe DisableEmailInterceptor do describe Gitlab::Email::Hook::DisableEmailInterceptor do
before do before do
Mail.register_interceptor(described_class) Mail.register_interceptor(described_class)
end end
......
...@@ -1366,7 +1366,8 @@ describe Notify do ...@@ -1366,7 +1366,8 @@ describe Notify do
it 'only sends the text template' do it 'only sends the text template' do
stub_application_setting(html_emails_enabled: false) stub_application_setting(html_emails_enabled: false)
EmailTemplateInterceptor.delivering_email(multipart_mail) Gitlab::Email::Hook::EmailTemplateInterceptor
.delivering_email(multipart_mail)
expect(multipart_mail).to have_part_with('text/plain') expect(multipart_mail).to have_part_with('text/plain')
expect(multipart_mail).not_to have_part_with('text/html') expect(multipart_mail).not_to have_part_with('text/html')
...@@ -1377,7 +1378,8 @@ describe Notify do ...@@ -1377,7 +1378,8 @@ describe Notify do
it 'sends a multipart message' do it 'sends a multipart message' do
stub_application_setting(html_emails_enabled: true) stub_application_setting(html_emails_enabled: true)
EmailTemplateInterceptor.delivering_email(multipart_mail) Gitlab::Email::Hook::EmailTemplateInterceptor
.delivering_email(multipart_mail)
expect(multipart_mail).to have_part_with('text/plain') expect(multipart_mail).to have_part_with('text/plain')
expect(multipart_mail).to have_part_with('text/html') expect(multipart_mail).to have_part_with('text/html')
......
...@@ -197,6 +197,22 @@ describe ProjectWiki do ...@@ -197,6 +197,22 @@ describe ProjectWiki do
end end
end end
describe '#find_sidebar' do
before do
create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
end
after do
subject.pages.each { |page| destroy_page(page.page) }
end
it 'finds the page defined as _sidebar' do
page = subject.find_page('_sidebar')
expect(page.content).to eq('This is an awesome Sidebar')
end
end
describe '#find_file' do describe '#find_file' do
shared_examples 'finding a wiki file' do shared_examples 'finding a wiki file' do
let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) } let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
......
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