Commit b0191139 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-03-27

# Conflicts:
#	app/models/ci/pipeline.rb
#	app/services/ci/create_pipeline_service.rb
#	app/services/ci/pipeline_trigger_service.rb
#	app/views/admin/application_settings/_form.html.haml
#	spec/features/admin/admin_settings_spec.rb
#	spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
#	spec/models/ci/pipeline_spec.rb

[ci skip]
parents b769f211 ab8f13c3
......@@ -49,7 +49,7 @@ gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-oauth2-generic', '~> 0.2.2'
gem 'omniauth-saml', '~> 1.10'
gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.4'
gem 'omniauth_crowd', '~> 2.2.0'
gem 'omniauth-authentiq', '~> 0.3.1'
gem 'rack-oauth2', '~> 1.2.1'
......
......@@ -547,7 +547,7 @@ GEM
nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
numerizer (0.1.1)
oauth (0.5.1)
oauth (0.5.4)
oauth2 (1.4.0)
faraday (>= 0.8, < 0.13)
jwt (~> 1.0)
......@@ -602,9 +602,9 @@ GEM
ruby-saml (~> 1.7)
omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0)
omniauth-twitter (1.2.1)
json (~> 1.3)
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
omniauth_crowd (2.2.3)
activesupport
nokogiri (>= 1.4.4)
......@@ -1157,7 +1157,7 @@ DEPENDENCIES
omniauth-oauth2-generic (~> 0.2.2)
omniauth-saml (~> 1.10)
omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0)
omniauth-twitter (~> 1.4)
omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12)
peek (~> 1.0.1)
......
import initSettingsPanels from '~/settings_panels';
document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels
initSettingsPanels();
});
......@@ -11,6 +11,14 @@ module Emails
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
end
def push_to_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil, new_commits: [], existing_commits: [])
setup_merge_request_mail(merge_request_id, recipient_id)
@new_commits = new_commits
@existing_commits = existing_commits
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id, reason = nil)
setup_merge_request_mail(merge_request_id, recipient_id)
......
......@@ -7,8 +7,11 @@ module Ci
include Presentable
include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize
<<<<<<< HEAD
prepend ::EE::Ci::Pipeline
=======
>>>>>>> upstream/master
belongs_to :project, inverse_of: :pipelines
belongs_to :user
......
......@@ -175,7 +175,7 @@ class Commit
if safe_message.blank?
no_commit_message
else
safe_message.split("\n", 2).first
safe_message.split(/[\r\n]/, 2).first
end
end
......
......@@ -48,7 +48,7 @@ class NotificationRecipient
when :custom
custom_enabled? || %i[participating mention].include?(@type)
when :watch, :participating
!excluded_watcher_action?
!action_excluded?
when :mention
@type == :mention
else
......@@ -96,13 +96,22 @@ class NotificationRecipient
end
end
def action_excluded?
excluded_watcher_action? || excluded_participating_action?
end
def excluded_watcher_action?
return false unless @custom_action
return false if notification_level == :custom
return false unless @custom_action && notification_level == :watch
NotificationSetting::EXCLUDED_WATCHER_EVENTS.include?(@custom_action)
end
def excluded_participating_action?
return false unless @custom_action && notification_level == :participating
NotificationSetting::EXCLUDED_PARTICIPATING_EVENTS.include?(@custom_action)
end
private
def read_ability
......
......@@ -33,6 +33,7 @@ class NotificationSetting < ActiveRecord::Base
:close_issue,
:reassign_issue,
:new_merge_request,
:push_to_merge_request,
:reopen_merge_request,
:close_merge_request,
:reassign_merge_request,
......@@ -41,10 +42,14 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline
].freeze
EXCLUDED_WATCHER_EVENTS = [
EXCLUDED_PARTICIPATING_EVENTS = [
:success_pipeline
].freeze
EXCLUDED_WATCHER_EVENTS = [
:push_to_merge_request
].push(*EXCLUDED_PARTICIPATING_EVENTS).freeze
def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source)
......
......@@ -641,9 +641,7 @@ class User < ActiveRecord::Base
end
def owned_projects
@owned_projects ||=
Project.where('namespace_id IN (?) OR namespace_id = ?',
owned_groups.select(:id), namespace.id).joins(:namespace)
@owned_projects ||= Project.from("(#{owned_projects_union.to_sql}) AS projects")
end
# Returns projects which user can admin issues on (for example to move an issue to that project).
......@@ -1218,6 +1216,15 @@ class User < ActiveRecord::Base
private
def owned_projects_union
Gitlab::SQL::Union.new([
Project.where(namespace: namespace),
Project.joins(:project_authorizations)
.where("projects.namespace_id <> ?", namespace.id)
.where(project_authorizations: { user_id: id, access_level: Gitlab::Access::OWNER })
], remove_duplicates: false)
end
def ci_projects_union
scope = { access_level: [Gitlab::Access::MASTER, Gitlab::Access::OWNER] }
groups = groups_projects.where(members: scope)
......
......@@ -8,10 +8,15 @@ module Ci
Gitlab::Ci::Pipeline::Chain::Validate::Repository,
Gitlab::Ci::Pipeline::Chain::Validate::Config,
Gitlab::Ci::Pipeline::Chain::Skip,
<<<<<<< HEAD
EE::Gitlab::Ci::Pipeline::Chain::Limit::Size,
Gitlab::Ci::Pipeline::Chain::Populate,
Gitlab::Ci::Pipeline::Chain::Create,
EE::Gitlab::Ci::Pipeline::Chain::Limit::Activity].freeze
=======
Gitlab::Ci::Pipeline::Chain::Populate,
Gitlab::Ci::Pipeline::Chain::Create].freeze
>>>>>>> upstream/master
def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, mirror_update: false, &block)
@pipeline = Ci::Pipeline.new
......
......@@ -20,6 +20,7 @@ module Ci
.execute(:trigger, ignore_skip_ci: true) do |pipeline|
pipeline.trigger_requests.build(trigger: trigger)
pipeline.variables.build(variables)
<<<<<<< HEAD
end
if pipeline.persisted?
......@@ -45,6 +46,8 @@ module Ci
pipeline.source_pipeline = source
pipeline.variables.build(variables)
=======
>>>>>>> upstream/master
end
if pipeline.persisted?
......@@ -60,12 +63,15 @@ module Ci
end
end
<<<<<<< HEAD
def job_from_token
strong_memoize(:job) do
Ci::Build.find_by_token(params[:token].to_s)
end
end
=======
>>>>>>> upstream/master
def variables
params[:variables].to_h.map do |key, value|
{ key: key, value: value }
......
......@@ -21,7 +21,7 @@ module MergeRequests
comment_mr_branch_presence_changed
end
comment_mr_with_commits
notify_about_push
mark_mr_as_wip_from_commits
execute_mr_web_hooks
reset_approvals_for_merge_requests
......@@ -158,8 +158,8 @@ module MergeRequests
end
end
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
# Add comment about pushing new commits to merge requests and send nofitication emails
def notify_about_push
return unless @commits.present?
merge_requests_for_source_branch.each do |merge_request|
......@@ -172,6 +172,8 @@ module MergeRequests
SystemNoteService.add_commits(merge_request, merge_request.project,
@current_user, new_commits,
existing_commits, @oldrev)
notification_service.push_to_merge_request(merge_request, @current_user, new_commits: new_commits, existing_commits: existing_commits)
end
end
......
......@@ -116,6 +116,16 @@ class NotificationService
new_resource_email(merge_request, :new_merge_request_email)
end
def push_to_merge_request(merge_request, current_user, new_commits: [], existing_commits: [])
new_commits = new_commits.map { |c| { short_id: c.short_id, title: c.title } }
existing_commits = existing_commits.map { |c| { short_id: c.short_id, title: c.title } }
recipients = NotificationRecipientService.build_recipients(merge_request, current_user, action: "push_to")
recipients.each do |recipient|
mailer.send(:push_to_merge_request_email, recipient.user.id, merge_request.id, current_user.id, recipient.reason, new_commits: new_commits, existing_commits: existing_commits).deliver_later
end
end
# When merge request text is updated, we should send an email to:
#
# * newly mentioned project team members with notification level higher than Participating
......
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :gravatar_enabled do
= f.check_box :gravatar_enabled
Gravatar enabled
.form-group
= f.label :default_projects_limit, class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :default_projects_limit, class: 'form-control'
.form-group
= f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_attachment_size, class: 'form-control'
.form-group
= f.label :session_expire_delay, 'Session duration (minutes)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :session_expire_delay, class: 'form-control'
%span.help-block#session_expire_delay_help_block GitLab restart is required to apply changes
.form-group
= f.label :user_oauth_applications, 'User OAuth applications', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_oauth_applications do
= f.check_box :user_oauth_applications
Allow users to register any application to use GitLab as an OAuth provider
.form-group
= f.label :user_default_external, 'New users set to external', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_default_external do
= f.check_box :user_default_external
Newly registered users will by default be external
= f.submit 'Save changes', class: 'btn btn-success'
......@@ -2,6 +2,7 @@
= form_errors(@application_setting)
%fieldset
<<<<<<< HEAD
%legend Visibility and Access Controls
.form-group
= f.label :default_branch_protection, class: 'control-label col-sm-2'
......@@ -285,6 +286,8 @@
= link_to icon('question-circle'), help_page_path('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
%fieldset
=======
>>>>>>> upstream/master
%legend Continuous Integration and Deployment
.form-group
.col-sm-offset-2.col-sm-10
......
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :help_page_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :help_page_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :help_page_hide_commercial_content do
= f.check_box :help_page_hide_commercial_content
Hide marketing-related entries from help
.form-group
= f.label :help_page_support_url, 'Support page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
%span.help-block#support_help_block Alternate support URL for help page
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :max_pages_size, 'Maximum size of pages (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_pages_size, class: 'form-control'
.help-block 0 for unlimited
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :pages_domain_verification_enabled do
= f.check_box :pages_domain_verification_enabled
Require users to prove ownership of custom domains
.help-block
Domain verification is an essential security measure for public GitLab
sites. Users are required to demonstrate they control a domain before
it is enabled
= link_to icon('question-circle'), help_page_path('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :password_authentication_enabled_for_web do
= f.check_box :password_authentication_enabled_for_web
Password authentication enabled for web interface
.help-block
When disabled, an external authentication provider must be used.
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :password_authentication_enabled_for_git do
= f.check_box :password_authentication_enabled_for_git
Password authentication enabled for Git over HTTP(S)
.help-block
When disabled, a Personal Access Token
- if Gitlab::Auth::LDAP::Config.enabled?
or LDAP password
must be used to authenticate.
- if omniauth_enabled? && button_based_providers.any?
.form-group
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2'
.col-sm-10
.btn-group{ data: { toggle: 'buttons' } }
- oauth_providers_checkboxes.each do |source|
= source
.form-group
= f.label :two_factor_authentication, 'Two-factor authentication', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :require_two_factor_authentication do
= f.check_box :require_two_factor_authentication
Require all users to setup Two-factor authentication
.form-group
= f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0'
.help-block Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication
.form-group
= f.label :home_page_url, 'Home page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block'
%span.help-block#home_help_block We will redirect non-logged in users to this page
.form-group
= f.label :after_sign_out_path, class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :after_sign_out_path, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'after_sign_out_path_help_block'
%span.help-block#after_sign_out_path_help_block We will redirect users to this page after they sign out
.form-group
= f.label :sign_in_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :signup_enabled do
= f.check_box :signup_enabled
Sign-up enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :send_user_confirmation_email do
= f.check_box :send_user_confirmation_email
Send confirmation email on sign-up
.form-group
= f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :domain_whitelist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.help-block ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :domain_blacklist_enabled do
= f.check_box :domain_blacklist_enabled
Enable domain blacklist for sign ups
.form-group
.col-sm-offset-2.col-sm-10
.radio
= label_tag :blacklist_type_file do
= radio_button_tag :blacklist_type, :file
.option-title
Upload blacklist file
.radio
= label_tag :blacklist_type_raw do
= radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?
.option-title
Enter blacklist manually
.form-group.blacklist-file
= f.label :domain_blacklist_file, 'Blacklist file', class: 'control-label col-sm-2'
.col-sm-10
= f.file_field :domain_blacklist_file, class: 'form-control', accept: '.txt,.conf'
.help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries.
.form-group.blacklist-raw
= f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :domain_blacklist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :after_sign_up_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
.help-block Markdown enabled
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :default_branch_protection, class: 'control-label col-sm-2'
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
.form-group.visibility-level-setting
= f.label :default_project_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new)
.form-group.visibility-level-setting
= f.label :default_snippet_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new)
.form-group.visibility-level-setting
= f.label :default_group_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_group_visibility, form: f, selected_level: @application_setting.default_group_visibility, form_model: Group.new)
.form-group
= f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
.col-sm-10
- checkbox_name = 'application_setting[restricted_visibility_levels][]'
= hidden_field_tag(checkbox_name)
- restricted_level_checkboxes('restricted-visibility-help', checkbox_name).each do |level|
.checkbox
= level
%span.help-block#restricted-visibility-help
Selected levels cannot be used by non-admin users for projects or snippets.
If the public level is restricted, user profiles are only visible to logged in users.
.form-group
= f.label :import_sources, class: 'control-label col-sm-2'
.col-sm-10
- import_sources_checkboxes('import-sources-help').each do |source|
.checkbox= source
%span.help-block#import-sources-help
Enabled sources for code import during project creation. OmniAuth must be configured for GitHub
= link_to "(?)", help_page_path("integration/github")
, Bitbucket
= link_to "(?)", help_page_path("integration/bitbucket")
and GitLab.com
= link_to "(?)", help_page_path("integration/gitlab")
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :project_export_enabled do
= f.check_box :project_export_enabled
Project export enabled
.form-group
%label.control-label.col-sm-2 Enabled Git access protocols
.col-sm-10
= select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control')
%span.help-block#clone-protocol-help
Allow only the selected protocols to be used for Git access.
- ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type|
- field_name = :"#{type}_key_restriction"
.form-group
= f.label field_name, "#{type.upcase} SSH keys", class: 'control-label col-sm-2'
.col-sm-10
= f.select field_name, key_restriction_options_for_select(type), {}, class: 'form-control'
= f.submit 'Save changes', class: "btn btn-success"
- breadcrumb_title "Settings"
- page_title "Settings"
- @content_class = "limit-container-width" unless fluid_layout
- expanded = Rails.env.test?
%h3.page-title Settings
%hr
= render 'form'
%section.settings.as-visibility-access.no-animate#js-visibility-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Visibility and access controls')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Set default and restrict visibility levels. Configure import sources and git access protocol.')
.settings-content
= render 'visibility_and_access'
%section.settings.as-account-limit.no-animate#js-account-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Account and limit settings')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Session expiration, projects limit and attachment size.')
.settings-content
= render 'account_and_limit'
%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Sign-up restrictions')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Configure the way a user creates a new account.')
.settings-content
= render 'signup'
%section.settings.as-signin.no-animate#js-signin-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Sign-in restrictions')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Set requirements for a user to sign-in. Enable mandatory two-factor authentication.')
.settings-content
= render 'signin'
%section.settings.as-help-page.no-animate#js-help-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Help page')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Help page text and support page url.')
.settings-content
= render 'help_page'
%section.settings.as-pages.no-animate#js-pages-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Pages')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Size and domain settings for static websites')
.settings-content
= render 'pages'
.prepend-top-20
= render 'form'
%h3
New commits were pushed to the merge request
= link_to(@merge_request.to_reference, project_merge_request_url(@merge_request.target_project, @merge_request))
by #{@current_user.name}
- if @existing_commits.any?
- count = @existing_commits.size
%ul
%li
- if count.one?
- commit_id = @existing_commits.first[:short_id]
= link_to(commit_id, project_commit_url(@merge_request.target_project, commit_id))
- else
= link_to(project_compare_url(@merge_request.target_project, from: @existing_commits.first[:short_id], to: @existing_commits.last[:short_id])) do
#{@existing_commits.first[:short_id]}...#{@existing_commits.last[:short_id]}
= precede '&nbsp;- ' do
- commits_text = "#{count} commit".pluralize(count)
#{commits_text} from branch `#{@merge_request.target_branch}`
- if @new_commits.any?
%ul
- @new_commits.each do |commit|
%li
= link_to(commit[:short_id], project_commit_url(@merge_request.target_project, commit[:short_id]))
= precede ' - ' do
#{commit[:title]}
New commits were pushed to the merge request #{@merge_request.to_reference} by #{@current_user.name}
\
#{url_for(project_merge_request_url(@merge_request.target_project, @merge_request))}
\
- if @existing_commits.any?
- count = @existing_commits.size
- commits_id = count.one? ? @existing_commits.first[:short_id] : "#{@existing_commits.first[:short_id]}...#{@existing_commits.last[:short_id]}"
- commits_text = "#{count} commit".pluralize(count)
* #{commits_id} - #{commits_text} from branch `#{@merge_request.target_branch}`
\
- @new_commits.each do |commit|
* #{commit[:short_id]} - #{raw commit[:title]}
---
title: Send notification emails when push to a merge request
merge_request: 7610
author: YarNayar
type: feature
---
title: Improves the performance of projects list page
merge_request: 17934
author:
type: performance
---
title: 'Cloning a repository over HTTPS with LDAP credentials causes a HTTP 401 Access denied'
merge_request: !17988
author: Horatiu Eugen Vlad
type: fixed
class AddPushToMergeRequestToNotificationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :notification_settings, :push_to_merge_request, :boolean
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180320182229) do
ActiveRecord::Schema.define(version: 20180323150945) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -1708,6 +1708,7 @@ ActiveRecord::Schema.define(version: 20180320182229) do
t.boolean "merge_merge_request"
t.boolean "failed_pipeline"
t.boolean "success_pipeline"
t.boolean "push_to_merge_request"
end
add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
......
......@@ -24,6 +24,7 @@ reopen_issue
close_issue
reassign_issue
new_merge_request
push_to_merge_request
reopen_merge_request
close_merge_request
reassign_merge_request
......@@ -75,6 +76,7 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab
| `close_issue` | boolean | no | Enable/disable this notification |
| `reassign_issue` | boolean | no | Enable/disable this notification |
| `new_merge_request` | boolean | no | Enable/disable this notification |
| `push_to_merge_request` | boolean | no | Enable/disable this notification |
| `reopen_merge_request` | boolean | no | Enable/disable this notification |
| `close_merge_request` | boolean | no | Enable/disable this notification |
| `reassign_merge_request` | boolean | no | Enable/disable this notification |
......@@ -141,6 +143,7 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab
| `close_issue` | boolean | no | Enable/disable this notification |
| `reassign_issue` | boolean | no | Enable/disable this notification |
| `new_merge_request` | boolean | no | Enable/disable this notification |
| `push_to_merge_request` | boolean | no | Enable/disable this notification |
| `reopen_merge_request` | boolean | no | Enable/disable this notification |
| `close_merge_request` | boolean | no | Enable/disable this notification |
| `reassign_merge_request` | boolean | no | Enable/disable this notification |
......@@ -164,6 +167,7 @@ Example responses:
"close_issue": false,
"reassign_issue": false,
"new_merge_request": false,
"push_to_merge_request": false,
"reopen_merge_request": false,
"close_merge_request": false,
"reassign_merge_request": false,
......
......@@ -67,7 +67,7 @@ Below is the table of events users can be notified of:
### Issue / Merge request events
In all of the below cases, the notification will be sent to:
In most of the below cases, the notification will be sent to:
- Participants:
- the author and assignee of the issue/merge request
- authors of comments on the issue/merge request
......@@ -87,6 +87,7 @@ In all of the below cases, the notification will be sent to:
| Reassign issue | The above, plus the old assignee |
| Reopen issue | |
| New merge request | |
| Push to merge request | Participants and Custom notification level with this event selected |
| Reassign merge request | The above, plus the old assignee |
| Close merge request | |
| Reopen merge request | |
......
......@@ -71,7 +71,11 @@ module Gitlab
authenticators.compact!
user if authenticators.find { |auth| auth.login(login, password) }
# return found user that was authenticated first for given login credentials
authenticators.find do |auth|
authenticated_user = auth.login(login, password)
break authenticated_user if authenticated_user
end
end
end
......
......@@ -8,7 +8,7 @@ module Gitlab
def login(login, password)
return false unless Gitlab::CurrentSettings.password_authentication_enabled_for_git?
user&.valid_password?(password)
return user if user&.valid_password?(password)
end
end
end
......
......@@ -12,30 +12,26 @@ module Gitlab
return unless Gitlab::Auth::LDAP::Config.enabled?
return unless login.present? && password.present?
auth = nil
# loop through providers until valid bind
# return found user that was authenticated by first provider for given login credentials
providers.find do |provider|
auth = new(provider)
auth.login(login, password) # true will exit the loop
break auth.user if auth.login(login, password) # true will exit the loop
end
# If (login, password) was invalid for all providers, the value of auth is now the last
# Gitlab::Auth::LDAP::Authentication instance we tried.
auth.user
end
def self.providers
Gitlab::Auth::LDAP::Config.providers
end
attr_accessor :ldap_user
def login(login, password)
@ldap_user = adapter.bind_as(
result = adapter.bind_as(
filter: user_filter(login),
size: 1,
password: password
)
return unless result
@user = Gitlab::Auth::LDAP::User.find_by_uid_and_provider(result.dn, provider)
end
def adapter
......@@ -56,12 +52,6 @@ module Gitlab
filter
end
def user
return unless ldap_user
Gitlab::Auth::LDAP::User.find_by_uid_and_provider(ldap_user.dn, provider)
end
end
end
end
......
......@@ -12,6 +12,7 @@ module Gitlab
@user = user
end
# Implementation must return user object if login successful
def login(login, password)
raise NotImplementedError
end
......
......@@ -3,7 +3,7 @@
cd "$(dirname "$0")/.."
# Use long options (e.g. --header instead of -H) for curl examples in documentation.
echo 'Checking for curl short options...'
echo '=> Checking for cURL short options...'
grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/ >/dev/null 2>&1
if [ $? == 0 ]
then
......@@ -15,7 +15,7 @@ fi
# Ensure that the CHANGELOG.md does not contain duplicate versions
DUPLICATE_CHANGELOG_VERSIONS=$(grep --extended-regexp '^## .+' CHANGELOG.md | sed -E 's| \(.+\)||' | sort -r | uniq -d)
echo 'Checking for CHANGELOG.md duplicate entries...'
echo '=> Checking for CHANGELOG.md duplicate entries...'
if [ "${DUPLICATE_CHANGELOG_VERSIONS}" != "" ]
then
echo '✖ ERROR: Duplicate versions in CHANGELOG.md:' >&2
......@@ -25,7 +25,7 @@ fi
# Make sure no files in doc/ are executable
EXEC_PERM_COUNT=$(find doc/ app/ -type f -perm 755 | wc -l)
echo 'Checking for executable permissions...'
echo '=> Checking for executable permissions...'
if [ "${EXEC_PERM_COUNT}" -ne 0 ]
then
echo '✖ ERROR: Executable permissions should not be used in documentation! Use `chmod 644` to the files in question:' >&2
......@@ -33,5 +33,33 @@ then
exit 1
fi
# Do not use 'README.md', instead use 'index.md'
# Number of 'README.md's as of 2018-03-26
NUMBER_READMES_CE=42
NUMBER_READMES_EE=46
FIND_READMES=$(find doc/ -name "README.md" | wc -l)
echo '=> Checking for new README.md files...'
if [ "${CI_PROJECT_NAME}" == 'gitlab-ce' ]
then
if [ ${FIND_READMES} -ne ${NUMBER_READMES_CE} ]
then
echo
echo ' ✖ ERROR: New README.md file(s) detected, prefer index.md over README.md.' >&2
echo ' https://docs.gitlab.com/ee/development/writing_documentation.html#location-and-naming-documents'
echo
exit 1
fi
elif [ "${CI_PROJECT_NAME}" == 'gitlab-ee' ]
then
if [ ${FIND_READMES} -ne $NUMBER_READMES_EE ]
then
echo
echo ' ✖ ERROR: New README.md file(s) detected, prefer index.md over README.md.' >&2
echo ' https://docs.gitlab.com/ee/development/writing_documentation.html#location-and-naming-documents'
echo
exit 1
fi
fi
echo "✔ Linting passed"
exit 0
......@@ -55,14 +55,19 @@ feature 'Admin disables Git access protocol' do
end
def disable_http_protocol
visit admin_application_settings_path
find('#application_setting_enabled_git_access_protocol').find(:xpath, 'option[2]').select_option
click_on 'Save'
switch_git_protocol(2)
end
def disable_ssh_protocol
switch_git_protocol(3)
end
def switch_git_protocol(value)
visit admin_application_settings_path
find('#application_setting_enabled_git_access_protocol').find(:xpath, 'option[3]').select_option
page.within('.as-visibility-access') do
find('#application_setting_enabled_git_access_protocol').find(:xpath, "option[#{value}]").select_option
click_on 'Save'
end
end
end
......@@ -10,18 +10,21 @@ feature 'Admin updates settings' do
end
scenario 'Change visibility settings' do
page.within('.as-visibility-access') do
choose "application_setting_default_project_visibility_20"
click_button 'Save'
click_button 'Save changes'
end
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Uncheck all restricted visibility levels' do
page.within('.as-visibility-access') do
find('#application_setting_visibility_level_0').set(false)
find('#application_setting_visibility_level_10').set(false)
find('#application_setting_visibility_level_20').set(false)
click_button 'Save'
click_button 'Save changes'
end
expect(page).to have_content "Application settings saved successfully"
expect(find('#application_setting_visibility_level_0')).not_to be_checked
......@@ -29,6 +32,7 @@ feature 'Admin updates settings' do
expect(find('#application_setting_visibility_level_20')).not_to be_checked
end
<<<<<<< HEAD
describe 'LDAP settings' do
context 'with LDAP enabled' do
scenario 'Change allow group owners to manage ldap' do
......@@ -60,13 +64,61 @@ feature 'Admin updates settings' do
fill_in 'Support page URL', with: 'http://example.com/help'
uncheck 'Project export enabled'
click_button 'Save'
=======
scenario 'Change Visibility and Access Controls' do
page.within('.as-visibility-access') do
uncheck 'Project export enabled'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Account and Limit Settings' do
page.within('.as-account-limit') do
uncheck 'Gravatar enabled'
click_button 'Save changes'
end
>>>>>>> upstream/master
expect(Gitlab::CurrentSettings.gravatar_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Sign-in restrictions' do
page.within('.as-signin') do
fill_in 'Home page URL', with: 'https://about.gitlab.com/'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.home_page_url).to eq "https://about.gitlab.com/"
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Help page' do
page.within('.as-help-page') do
fill_in 'Help page text', with: 'Example text'
check 'Hide marketing-related entries from help'
fill_in 'Support page URL', with: 'http://example.com/help'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.help_page_text).to eq "Example text"
expect(Gitlab::CurrentSettings.help_page_hide_commercial_content).to be_truthy
expect(Gitlab::CurrentSettings.help_page_support_url).to eq "http://example.com/help"
expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Pages settings' do
page.within('.as-pages') do
fill_in 'Maximum size of pages (MB)', with: 15
check 'Require users to prove ownership of custom domains'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.max_pages_size).to eq 15
expect(Gitlab::CurrentSettings.pages_domain_verification_enabled?).to be_truthy
expect(page).to have_content "Application settings saved successfully"
end
......@@ -106,18 +158,22 @@ feature 'Admin updates settings' do
context 'sign-in restrictions', :js do
it 'de-activates oauth sign-in source' do
page.within('.as-signin') do
find('input#application_setting_enabled_oauth_sign_in_sources_[value=gitlab]').send_keys(:return)
expect(find('.btn', text: 'GitLab.com')).not_to have_css('.active')
end
end
end
scenario 'Change Keys settings' do
page.within('.as-visibility-access') do
select 'Are forbidden', from: 'RSA SSH keys'
select 'Are allowed', from: 'DSA SSH keys'
select 'Must be at least 384 bits', from: 'ECDSA SSH keys'
select 'Are forbidden', from: 'ED25519 SSH keys'
click_on 'Save'
click_on 'Save changes'
end
forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE.to_s
......
......@@ -315,13 +315,19 @@ describe Gitlab::Auth do
it "tries to autheticate with db before ldap" do
expect(Gitlab::Auth::LDAP::Authentication).not_to receive(:login)
gl_auth.find_with_user_password(username, password)
expect(gl_auth.find_with_user_password(username, password)).to eq(user)
end
it "does not find user by using ldap as fallback to for authentication" do
expect(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(nil)
expect(gl_auth.find_with_user_password('ldap_user', 'password')).to be_nil
end
it "uses ldap as fallback to for authentication" do
expect(Gitlab::Auth::LDAP::Authentication).to receive(:login)
it "find new user by using ldap as fallback to for authentication" do
expect(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(user)
gl_auth.find_with_user_password('ldap_user', 'password')
expect(gl_auth.find_with_user_password('ldap_user', 'password')).to eq(user)
end
end
......
require 'spec_helper'
describe Gitlab::Ci::Pipeline::Chain::Populate do
<<<<<<< HEAD
set(:project) { create(:project, :repository) }
=======
set(:project) { create(:project) }
>>>>>>> upstream/master
set(:user) { create(:user) }
let(:pipeline) do
......@@ -139,7 +143,11 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
end
let(:pipeline) do
<<<<<<< HEAD
build(:ci_pipeline, ref: 'master', project: project, config: config)
=======
build(:ci_pipeline, ref: 'master', config: config)
>>>>>>> upstream/master
end
it 'populates pipeline according to used policies' do
......
......@@ -238,8 +238,12 @@ describe Ci::Pipeline, :mailer do
describe 'pipeline stages' do
describe '#stage_seeds' do
<<<<<<< HEAD
let(:project) { create(:project, :repository) }
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
=======
let(:pipeline) { build(:ci_pipeline, config: config) }
>>>>>>> upstream/master
let(:config) { { rspec: { script: 'rake' } } }
it 'returns preseeded stage seeds object' do
......@@ -254,10 +258,17 @@ describe Ci::Pipeline, :mailer do
rspec: { stage: 'test', script: 'rspec' },
spinach: { stage: 'test', script: 'spinach' } }
end
<<<<<<< HEAD
it 'correctly fabricates a stage seeds object' do
seeds = pipeline.stage_seeds
=======
it 'correctly fabricates a stage seeds object' do
seeds = pipeline.stage_seeds
>>>>>>> upstream/master
expect(seeds.size).to eq 2
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.second.attributes[:name]).to eq 'deploy'
......@@ -269,7 +280,11 @@ describe Ci::Pipeline, :mailer do
context 'when refs policy is specified' do
let(:pipeline) do
<<<<<<< HEAD
build(:ci_pipeline, ref: 'feature', tag: true, project: project, config: config)
=======
build(:ci_pipeline, ref: 'feature', tag: true, config: config)
>>>>>>> upstream/master
end
let(:config) do
......@@ -287,6 +302,7 @@ describe Ci::Pipeline, :mailer do
end
context 'when source policy is specified' do
<<<<<<< HEAD
let(:pipeline) do
build(:ci_pipeline, source: :schedule, project: project, config: config)
end
......@@ -294,8 +310,25 @@ describe Ci::Pipeline, :mailer do
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] } }
=======
let(:pipeline) { build(:ci_pipeline, source: :schedule, config: config) }
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] } }
end
it 'returns stage seeds only assigned to schedules' do
seeds = pipeline.stage_seeds
expect(seeds.size).to eq 1
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
>>>>>>> upstream/master
end
end
<<<<<<< HEAD
it 'returns stage seeds only assigned to schedules' do
seeds = pipeline.stage_seeds
......@@ -305,6 +338,8 @@ describe Ci::Pipeline, :mailer do
end
end
=======
>>>>>>> upstream/master
context 'when kubernetes policy is specified' do
let(:config) do
{
......@@ -316,12 +351,21 @@ describe Ci::Pipeline, :mailer do
}
}
end
<<<<<<< HEAD
context 'when kubernetes is active' do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'returns seeds for kubernetes dependent job' do
seeds = pipeline.stage_seeds
=======
context 'when kubernetes is active' do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'returns seeds for kubernetes dependent job' do
seeds = pipeline.stage_seeds
>>>>>>> upstream/master
expect(seeds.size).to eq 2
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
expect(seeds.dig(1, 0, :name)).to eq 'production'
......@@ -329,7 +373,11 @@ describe Ci::Pipeline, :mailer do
end
context 'when user configured kubernetes from Integration > Kubernetes' do
<<<<<<< HEAD
let(:project) { create(:kubernetes_project, :repository) }
=======
let(:project) { create(:kubernetes_project) }
>>>>>>> upstream/master
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
......@@ -357,17 +405,28 @@ describe Ci::Pipeline, :mailer do
describe '#seeds_size' do
context 'when refs policy is specified' do
<<<<<<< HEAD
let(:project) { create(:project, :repository) }
=======
>>>>>>> upstream/master
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
spinach: { stage: 'test', script: 'spinach', only: ['tags'] } }
end
<<<<<<< HEAD
let(:pipeline) do
build(:ci_pipeline, ref: 'feature', tag: true, project: project, config: config)
end
=======
let(:pipeline) do
build(:ci_pipeline, ref: 'feature', tag: true, config: config)
end
>>>>>>> upstream/master
it 'returns real seeds size' do
expect(pipeline.seeds_size).to eq 1
end
......
......@@ -24,6 +24,14 @@ describe MergeRequests::RefreshService do
merge_when_pipeline_succeeds: true,
merge_user: @user)
@another_merge_request = create(:merge_request,
source_project: @project,
source_branch: 'master',
target_branch: 'test',
target_project: @project,
merge_when_pipeline_succeeds: true,
merge_user: @user)
@fork_merge_request = create(:merge_request,
source_project: @fork_project,
source_branch: 'master',
......@@ -55,9 +63,11 @@ describe MergeRequests::RefreshService do
context 'push to origin repo source branch' do
let(:refresh_service) { service.new(@project, @user) }
let(:notification_service) { spy('notification_service') }
before do
allow(refresh_service).to receive(:execute_hooks)
allow(NotificationService).to receive(:new) { notification_service }
end
it 'executes hooks with update action' do
......@@ -67,6 +77,11 @@ describe MergeRequests::RefreshService do
expect(refresh_service).to have_received(:execute_hooks)
.with(@merge_request, 'update', old_rev: @oldrev)
expect(notification_service).to have_received(:push_to_merge_request)
.with(@merge_request, @user, new_commits: anything, existing_commits: anything)
expect(notification_service).to have_received(:push_to_merge_request)
.with(@another_merge_request, @user, new_commits: anything, existing_commits: anything)
expect(@merge_request.notes).not_to be_empty
expect(@merge_request).to be_open
expect(@merge_request.merge_when_pipeline_succeeds).to be_falsey
......@@ -125,11 +140,13 @@ describe MergeRequests::RefreshService do
context 'push to origin repo source branch when an MR was reopened' do
let(:refresh_service) { service.new(@project, @user) }
let(:notification_service) { spy('notification_service') }
before do
@merge_request.update(state: :opened)
allow(refresh_service).to receive(:execute_hooks)
allow(NotificationService).to receive(:new) { notification_service }
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
end
......@@ -137,6 +154,10 @@ describe MergeRequests::RefreshService do
it 'executes hooks with update action' do
expect(refresh_service).to have_received(:execute_hooks)
.with(@merge_request, 'update', old_rev: @oldrev)
expect(notification_service).to have_received(:push_to_merge_request)
.with(@merge_request, @user, new_commits: anything, existing_commits: anything)
expect(notification_service).to have_received(:push_to_merge_request)
.with(@another_merge_request, @user, new_commits: anything, existing_commits: anything)
expect(@merge_request.notes).not_to be_empty
expect(@merge_request).to be_open
......
......@@ -1132,6 +1132,36 @@ describe NotificationService, :mailer do
end
end
describe '#push_to_merge_request' do
before do
update_custom_notification(:push_to_merge_request, @u_guest_custom, resource: project)
update_custom_notification(:push_to_merge_request, @u_custom_global)
end
it do
notification.push_to_merge_request(merge_request, @u_disabled)
should_email(merge_request.assignee)
should_email(@u_guest_custom)
should_email(@u_custom_global)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
should_not_email(@u_watcher)
should_not_email(@u_guest_watcher)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
should_not_email(@u_lazy_participant)
end
it_behaves_like 'participating notifications' do
let(:participant) { create(:user, username: 'user-participant') }
let(:issuable) { merge_request }
let(:notification_trigger) { notification.push_to_merge_request(merge_request, @u_disabled) }
end
end
describe '#relabel_merge_request' do
let(:group_label_1) { create(:group_label, group: group, title: 'Group Label 1', merge_requests: [merge_request]) }
let(:group_label_2) { create(:group_label, group: group, title: 'Group Label 2') }
......
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