Merge remote-tracking branch 'origin/master' into fix-comment-on-diff-ajax-loading
This commit is contained in:
commit
8a829c9738
59 changed files with 634 additions and 76 deletions
14
CHANGELOG
14
CHANGELOG
|
@ -1,17 +1,21 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.5.0 (unreleased)
|
||||
- Add "visibility" flag to GET /projects api endpoint
|
||||
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
|
||||
|
||||
v 8.4.0 (unreleased)
|
||||
- Fix diff comments loaded by AJAX to load comment with diff in discussion tab
|
||||
- Allow LDAP users to change their email if it was not set by the LDAP server
|
||||
- Ensure Gravatar host looks like an actual host
|
||||
- Consider re-assign as a mention from a notification point of view
|
||||
- Add pagination headers to already paginated API resources
|
||||
- Properly generate diff of orphan commits, like the first commit in a repository
|
||||
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
|
||||
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
|
||||
- Improved performance of finding issues for an entire group (Yorick Peterse)
|
||||
- Added custom application performance measuring system powered by InfluxDB (Yorick Peterse)
|
||||
- Autocomplete data is now always loaded, instead of when focusing a comment text area
|
||||
- Improved performance of finding issues for an entire group
|
||||
- Added custom application performance measuring system powered by InfluxDB
|
||||
- Gracefully handle invalid UTF-8 sequences in Markdown links (Stan Hu)
|
||||
- Bump fog to 1.36.0 (Stan Hu)
|
||||
- Add user's last used IP addresses to admin page (Stan Hu)
|
||||
- Add housekeeping function to project settings page
|
||||
|
@ -62,13 +66,15 @@ v 8.4.0 (unreleased)
|
|||
- Autosize Markdown textareas
|
||||
- Import GitHub wiki into GitLab
|
||||
- Add reporters ability to download and browse build artifacts (Andrew Johnson)
|
||||
- Autofill referring url in message box when reporting user abuse. (Josh Frye)
|
||||
- Autofill referring url in message box when reporting user abuse.
|
||||
- Remove leading comma on award emoji when the user is the first to award the emoji (Zeger-Jan van de Weg)
|
||||
- Add build artifacts browser
|
||||
- Improve UX in builds artifacts browser
|
||||
- Increase default size of `data` column in `events` table when using MySQL
|
||||
- Expose button to CI Lint tool on project builds page
|
||||
- Fix: Creator should be added as a master of the project on creation
|
||||
- Added X-GitLab-... headers to emails from CI and Email On Push services (Anton Baklanov)
|
||||
- Add IP check against DNSBLs at account sign-up
|
||||
|
||||
v 8.3.4
|
||||
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
|
||||
|
|
5
Gemfile
5
Gemfile
|
@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0'
|
|||
|
||||
# Extracting information from a git repository
|
||||
# Provide access to Gitlab::Git library
|
||||
gem "gitlab_git", '~> 7.2.22'
|
||||
gem "gitlab_git", '~> 7.2.23'
|
||||
|
||||
# LDAP Auth
|
||||
# GitLab fork with several improvements to original library. For full list of changes
|
||||
|
@ -293,6 +293,9 @@ end
|
|||
|
||||
group :production do
|
||||
gem "gitlab_meta", '7.0'
|
||||
|
||||
# Sentry integration
|
||||
gem 'sentry-raven'
|
||||
end
|
||||
|
||||
gem "newrelic_rpm", '~> 3.9.4.245'
|
||||
|
|
|
@ -356,7 +356,7 @@ GEM
|
|||
posix-spawn (~> 0.3)
|
||||
gitlab_emoji (0.2.0)
|
||||
gemojione (~> 2.1)
|
||||
gitlab_git (7.2.22)
|
||||
gitlab_git (7.2.23)
|
||||
activesupport (~> 4.0)
|
||||
charlock_holmes (~> 0.7.3)
|
||||
github-linguist (~> 4.7.0)
|
||||
|
@ -725,6 +725,8 @@ GEM
|
|||
activesupport (>= 3.1, < 4.3)
|
||||
select2-rails (3.5.9.3)
|
||||
thor (~> 0.14)
|
||||
sentry-raven (0.15.3)
|
||||
faraday (>= 0.7.6)
|
||||
settingslogic (2.0.9)
|
||||
sexp_processor (4.6.0)
|
||||
sham_rack (1.3.6)
|
||||
|
@ -932,7 +934,7 @@ DEPENDENCIES
|
|||
github-markup (~> 1.3.1)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab_emoji (~> 0.2.0)
|
||||
gitlab_git (~> 7.2.22)
|
||||
gitlab_git (~> 7.2.23)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.1.0)
|
||||
|
@ -1008,6 +1010,7 @@ DEPENDENCIES
|
|||
sdoc (~> 0.3.20)
|
||||
seed-fu (~> 2.3.5)
|
||||
select2-rails (~> 3.5.9)
|
||||
sentry-raven
|
||||
settingslogic (~> 2.0.9)
|
||||
sham_rack
|
||||
shoulda-matchers (~> 2.8.0)
|
||||
|
|
|
@ -44,7 +44,6 @@ class @AwardsHandler
|
|||
decrementCounter: (emoji) ->
|
||||
counter = @findEmojiIcon(emoji).siblings(".counter")
|
||||
emojiIcon = counter.parent()
|
||||
|
||||
if parseInt(counter.text()) > 1
|
||||
counter.text(parseInt(counter.text()) - 1)
|
||||
emojiIcon.removeClass("active")
|
||||
|
@ -60,20 +59,18 @@ class @AwardsHandler
|
|||
removeMeFromAuthorList: (emoji) ->
|
||||
award_block = @findEmojiIcon(emoji).parent()
|
||||
authors = award_block.attr("data-original-title").split(", ")
|
||||
authors = _.without(authors, "me").join(", ")
|
||||
award_block.attr("title", authors)
|
||||
authors.splice(authors.indexOf("me"),1)
|
||||
award_block.closest(".award").attr("data-original-title", authors.join(", "))
|
||||
@resetTooltip(award_block)
|
||||
|
||||
addMeToAuthorList: (emoji) ->
|
||||
award_block = @findEmojiIcon(emoji).parent()
|
||||
authors = _.compact(award_block.attr("data-original-title").split(", "))
|
||||
origTitle = award_block.attr("data-original-title").trim()
|
||||
authors = []
|
||||
if origTitle
|
||||
authors = origTitle.split(', ')
|
||||
authors.push("me")
|
||||
|
||||
if authors.length == 1
|
||||
award_block.attr("title", "me")
|
||||
else
|
||||
award_block.attr("title", authors.join(", "))
|
||||
|
||||
award_block.attr("title", authors.join(", "))
|
||||
@resetTooltip(award_block)
|
||||
|
||||
resetTooltip: (award) ->
|
||||
|
|
|
@ -87,7 +87,6 @@ class Dispatcher
|
|||
new GroupAvatar()
|
||||
when 'projects:tree:show'
|
||||
new TreeView()
|
||||
shortcut_handler = new ShortcutsTree()
|
||||
when 'projects:find_file:show'
|
||||
shortcut_handler = true
|
||||
when 'projects:blob:show'
|
||||
|
|
|
@ -4,6 +4,7 @@ class @Shortcuts
|
|||
Mousetrap.reset()
|
||||
Mousetrap.bind('?', @selectiveHelp)
|
||||
Mousetrap.bind('s', Shortcuts.focusSearch)
|
||||
Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
|
||||
|
||||
selectiveHelp: (e) =>
|
||||
Shortcuts.showHelp(e, @enabledHelp)
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
class @ShortcutsTree extends ShortcutsNavigation
|
||||
constructor: ->
|
||||
super()
|
||||
Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file'))
|
|
@ -6,7 +6,7 @@ class @Star
|
|||
$starIcon = $this.find('i')
|
||||
|
||||
toggleStar = (isStarred) ->
|
||||
$this.parent().find('span.count').text data.star_count
|
||||
$this.parent().find('.star-count').text data.star_count
|
||||
if isStarred
|
||||
$starSpan.removeClass('starred').text 'Star'
|
||||
$starIcon.removeClass('fa-star').addClass 'fa-star-o'
|
||||
|
@ -19,4 +19,4 @@ class @Star
|
|||
return
|
||||
).on 'ajax:error', (e, xhr, status, error) ->
|
||||
new Flash('Star toggle failed. Try again later.', 'alert')
|
||||
return
|
||||
return
|
||||
|
|
|
@ -26,6 +26,7 @@ $gl-vert-padding: 6px;
|
|||
$gl-padding-top:10px;
|
||||
$gl-avatar-size: 46px;
|
||||
$secondary-text: #7f8fa4;
|
||||
$error-exclamation-point: #E62958;
|
||||
|
||||
/*
|
||||
* Color schema
|
||||
|
|
|
@ -558,3 +558,9 @@ pre.light-well {
|
|||
width: 101%;
|
||||
}
|
||||
}
|
||||
|
||||
.cannot-be-merged,
|
||||
.cannot-be-merged:hover {
|
||||
color: #E62958;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
|
|
@ -74,9 +74,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
:metrics_timeout,
|
||||
:metrics_method_call_threshold,
|
||||
:metrics_sample_interval,
|
||||
:ip_blocking_enabled,
|
||||
:dnsbl_servers_list,
|
||||
:recaptcha_enabled,
|
||||
:recaptcha_site_key,
|
||||
:recaptcha_private_key,
|
||||
:sentry_enabled,
|
||||
:sentry_dsn,
|
||||
restricted_visibility_levels: [],
|
||||
import_sources: []
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base
|
|||
before_action :check_password_expiration
|
||||
before_action :check_2fa_requirement
|
||||
before_action :ldap_security_check
|
||||
before_action :sentry_user_context
|
||||
before_action :default_headers
|
||||
before_action :add_gon_variables
|
||||
before_action :configure_permitted_parameters, if: :devise_controller?
|
||||
|
@ -41,6 +42,16 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
protected
|
||||
|
||||
def sentry_user_context
|
||||
if Rails.env.production? && current_application_settings.sentry_enabled && current_user
|
||||
Raven.user_context(
|
||||
id: current_user.id,
|
||||
email: current_user.email,
|
||||
username: current_user.username,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
|
||||
# https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
|
||||
def authenticate_user_from_token!
|
||||
|
|
|
@ -8,6 +8,11 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
|
||||
def create
|
||||
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
|
||||
if Gitlab::IpCheck.new(request.remote_ip).spam?
|
||||
flash[:alert] = 'Could not create an account. This IP is listed for spam.'
|
||||
return render action: 'new'
|
||||
end
|
||||
|
||||
super
|
||||
else
|
||||
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."
|
||||
|
|
|
@ -3,13 +3,26 @@ module Emails
|
|||
def build_fail_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
add_project_headers
|
||||
add_build_headers
|
||||
headers['X-GitLab-Build-Status'] = "failed"
|
||||
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
def build_success_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
add_project_headers
|
||||
add_build_headers
|
||||
headers['X-GitLab-Build-Status'] = "success"
|
||||
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
private
|
||||
def add_build_headers
|
||||
headers['X-GitLab-Build-Id'] = @build.id
|
||||
headers['X-GitLab-Build-Ref'] = @build.ref
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,7 +43,7 @@ module Emails
|
|||
@current_user = @created_by = User.find(created_by_id)
|
||||
@access_level = access_level
|
||||
@invite_email = invite_email
|
||||
|
||||
|
||||
@target_url = namespace_project_url(@project.namespace, @project)
|
||||
|
||||
mail(to: @created_by.notification_email,
|
||||
|
@ -65,6 +65,10 @@ module Emails
|
|||
|
||||
# used in notify layout
|
||||
@target_url = @message.target_url
|
||||
@project = Project.find project_id
|
||||
|
||||
add_project_headers
|
||||
headers['X-GitLab-Author'] = @message.author_username
|
||||
|
||||
mail(from: sender(@message.author_id, @message.send_from_committer_email?),
|
||||
reply_to: @message.reply_to,
|
||||
|
|
|
@ -100,12 +100,7 @@ class Notify < BaseMailer
|
|||
end
|
||||
|
||||
def mail_thread(model, headers = {})
|
||||
if @project
|
||||
headers['X-GitLab-Project'] = @project.name
|
||||
headers['X-GitLab-Project-Id'] = @project.id
|
||||
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
|
||||
end
|
||||
|
||||
add_project_headers
|
||||
headers["X-GitLab-#{model.class.name}-ID"] = model.id
|
||||
headers['X-GitLab-Reply-Key'] = reply_key
|
||||
|
||||
|
@ -152,4 +147,12 @@ class Notify < BaseMailer
|
|||
def reply_key
|
||||
@reply_key ||= SentNotification.reply_key
|
||||
end
|
||||
|
||||
def add_project_headers
|
||||
return unless @project
|
||||
|
||||
headers['X-GitLab-Project'] = @project.name
|
||||
headers['X-GitLab-Project-Id'] = @project.id
|
||||
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
# recaptcha_site_key :string
|
||||
# recaptcha_private_key :string
|
||||
# metrics_port :integer default(8089)
|
||||
# sentry_enabled :boolean default(FALSE)
|
||||
# sentry_dsn :string
|
||||
# ip_blocking_enabled :boolean default(FALSE)
|
||||
# dns_blacklist_threshold :float default(0.33)
|
||||
#
|
||||
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
|
@ -82,6 +86,10 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
presence: true,
|
||||
if: :recaptcha_enabled
|
||||
|
||||
validates :sentry_dsn,
|
||||
presence: true,
|
||||
if: :sentry_enabled
|
||||
|
||||
validates_each :restricted_visibility_levels do |record, attr, value|
|
||||
unless value.nil?
|
||||
value.each do |level|
|
||||
|
|
|
@ -33,7 +33,7 @@ class Note < ActiveRecord::Base
|
|||
participant :author
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :noteable, polymorphic: true
|
||||
belongs_to :noteable, polymorphic: true, touch: true
|
||||
belongs_to :author, class_name: "User"
|
||||
belongs_to :updated_by, class_name: "User"
|
||||
|
||||
|
|
|
@ -272,6 +272,10 @@ class Project < ActiveRecord::Base
|
|||
query: "%#{query.try(:downcase)}%")
|
||||
end
|
||||
|
||||
def search_by_visibility(level)
|
||||
where(visibility_level: Gitlab::VisibilityLevel.const_get(level.upcase))
|
||||
end
|
||||
|
||||
def search_by_title(query)
|
||||
where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%")
|
||||
end
|
||||
|
|
|
@ -664,7 +664,10 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def all_emails
|
||||
[self.email, *self.emails.map(&:email)]
|
||||
all_emails = []
|
||||
all_emails << self.email unless self.temp_oauth_email?
|
||||
all_emails.concat(self.emails.map(&:email))
|
||||
all_emails
|
||||
end
|
||||
|
||||
def hook_attrs
|
||||
|
|
|
@ -212,6 +212,22 @@
|
|||
|
||||
%fieldset
|
||||
%legend Spam and Anti-bot Protection
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :ip_blocking_enabled do
|
||||
= f.check_box :ip_blocking_enabled
|
||||
Enable IP check against blacklist at sign-up
|
||||
.help-block Helps preventing accounts creation from 'known spam sources'
|
||||
|
||||
.form-group
|
||||
= f.label :dnsbl_servers_list, class: 'control-label col-sm-2' do
|
||||
DNSBL servers list
|
||||
.col-sm-10
|
||||
= f.text_field :dnsbl_servers_list, class: 'form-control'
|
||||
.help-block
|
||||
Please enter DNSBL servers separated with comma
|
||||
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
|
@ -226,11 +242,30 @@
|
|||
= f.text_field :recaptcha_site_key, class: 'form-control'
|
||||
.help-block
|
||||
Generate site and private keys here:
|
||||
%a{ href: 'http://www.google.com/recaptcha', target: 'blank'} http://www.google.com/recaptcha
|
||||
%a{ href: 'http://www.google.com/recaptcha', target: '_blank'} http://www.google.com/recaptcha
|
||||
.form-group
|
||||
= f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'control-label col-sm-2'
|
||||
.col-sm-10
|
||||
= f.text_field :recaptcha_private_key, class: 'form-control'
|
||||
|
||||
%fieldset
|
||||
%legend Error Reporting and Logging
|
||||
%p
|
||||
These settings require a restart to take effect.
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :sentry_enabled do
|
||||
= f.check_box :sentry_enabled
|
||||
Enable Sentry
|
||||
.help-block
|
||||
Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here:
|
||||
%a{ href: 'https://getsentry.com', target: '_blank' } https://getsentry.com
|
||||
|
||||
.form-group
|
||||
= f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2'
|
||||
.col-sm-10
|
||||
= f.text_field :sentry_dsn, class: 'form-control'
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Save', class: 'btn btn-primary'
|
||||
|
|
|
@ -37,3 +37,6 @@
|
|||
%h1.title= title
|
||||
|
||||
= render 'shared/outdated_browser'
|
||||
- if @project && !@project.empty_repo?
|
||||
:javascript
|
||||
var findFileURL = "#{namespace_project_find_file_path(@project.namespace, @project, @ref || @project.repository.root_ref)}";
|
|
@ -21,10 +21,10 @@
|
|||
.form-group
|
||||
= f.label :email, class: "control-label"
|
||||
.col-sm-10
|
||||
- if @user.ldap_user?
|
||||
- if @user.ldap_user? && @user.ldap_email?
|
||||
= f.text_field :email, class: "form-control", required: true, readonly: true
|
||||
%span.help-block.light
|
||||
Email is read-only for LDAP user
|
||||
Your email address was automatically set based on the LDAP server.
|
||||
- else
|
||||
- if @user.temp_oauth_email?
|
||||
= f.text_field :email, class: "form-control", required: true, value: nil
|
||||
|
|
|
@ -6,4 +6,3 @@
|
|||
%span.str-truncated
|
||||
= link_to directory.name, path_to_directory
|
||||
%td
|
||||
%td
|
||||
|
|
|
@ -7,5 +7,3 @@
|
|||
= link_to file.name, path_to_file
|
||||
%td
|
||||
= number_to_human_size(file.metadata[:size], precision: 2)
|
||||
%td
|
||||
= number_to_human_size(file.metadata[:zipped], precision: 2)
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
%tr
|
||||
%th Name
|
||||
%th Size
|
||||
%th Compressed to
|
||||
= render partial: 'tree_directory', collection: @entry.directories(parent: true), as: :directory
|
||||
= render partial: 'tree_file', collection: @entry.files, as: :file
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
|
||||
= @project.path
|
||||
%li.file-finder
|
||||
%input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path'}
|
||||
%input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path', autocomplete: 'off'}
|
||||
|
||||
%div.tree-content-holder
|
||||
.table-holder
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
.value
|
||||
- if issuable.assignee
|
||||
%strong= link_to_member(@project, issuable.assignee, size: 24)
|
||||
- if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee)
|
||||
%a.pull-right.cannot-be-merged{href: '#', data: {toggle: 'tooltip'}, title: 'Not allowed to merge'}
|
||||
= icon('exclamation-triangle')
|
||||
- else
|
||||
.light None
|
||||
|
||||
|
|
|
@ -7,8 +7,11 @@ if defined?(Unicorn)
|
|||
# Unicorn self-process killer
|
||||
require 'unicorn/worker_killer'
|
||||
|
||||
min = (ENV['GITLAB_UNICORN_MEMORY_MIN'] || 300 * 1 << 20).to_i
|
||||
max = (ENV['GITLAB_UNICORN_MEMORY_MAX'] || 350 * 1 << 20).to_i
|
||||
|
||||
# Max memory size (RSS) per worker
|
||||
use Unicorn::WorkerKiller::Oom, (200 * (1 << 20)), (250 * (1 << 20))
|
||||
use Unicorn::WorkerKiller::Oom, min, max
|
||||
end
|
||||
end
|
||||
|
||||
|
|
19
config/initializers/sentry.rb
Normal file
19
config/initializers/sentry.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
require 'gitlab/current_settings'
|
||||
include Gitlab::CurrentSettings
|
||||
|
||||
if Rails.env.production?
|
||||
# allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done
|
||||
begin
|
||||
sentry_enabled = current_application_settings.sentry_enabled
|
||||
rescue
|
||||
sentry_enabled = false
|
||||
end
|
||||
|
||||
if sentry_enabled
|
||||
Raven.configure do |config|
|
||||
config.dsn = current_application_settings.sentry_dsn
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
class AddSentryToApplicationSettings < ActiveRecord::Migration
|
||||
def change
|
||||
change_table :application_settings do |t|
|
||||
t.boolean :sentry_enabled, default: false
|
||||
t.string :sentry_dsn
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
class AddIpBlockingSettingsToApplicationSettings < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :application_settings, :ip_blocking_enabled, :boolean, default: false
|
||||
add_column :application_settings, :dnsbl_servers_list, :text
|
||||
end
|
||||
end
|
30
db/migrate/20160119145451_add_ldap_email_to_users.rb
Normal file
30
db/migrate/20160119145451_add_ldap_email_to_users.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
class AddLdapEmailToUsers < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :users, :ldap_email, :boolean, default: false, null: false
|
||||
|
||||
if Gitlab::Database.mysql?
|
||||
execute %{
|
||||
UPDATE users, identities
|
||||
SET users.ldap_email = TRUE
|
||||
WHERE identities.user_id = users.id
|
||||
AND users.email LIKE 'temp-email-for-oauth%'
|
||||
AND identities.provider LIKE 'ldap%'
|
||||
AND identities.extern_uid IS NOT NULL
|
||||
}
|
||||
else
|
||||
execute %{
|
||||
UPDATE users
|
||||
SET ldap_email = TRUE
|
||||
FROM identities
|
||||
WHERE identities.user_id = users.id
|
||||
AND users.email LIKE 'temp-email-for-oauth%'
|
||||
AND identities.provider LIKE 'ldap%'
|
||||
AND identities.extern_uid IS NOT NULL
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :users, :ldap_email
|
||||
end
|
||||
end
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160119112418) do
|
||||
ActiveRecord::Schema.define(version: 20160120130905) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -62,6 +62,10 @@ ActiveRecord::Schema.define(version: 20160119112418) do
|
|||
t.string "recaptcha_private_key"
|
||||
t.integer "metrics_port", default: 8089
|
||||
t.integer "metrics_sample_interval", default: 15
|
||||
t.boolean "sentry_enabled", default: false
|
||||
t.string "sentry_dsn"
|
||||
t.boolean "ip_blocking_enabled", default: false
|
||||
t.text "dnsbl_servers_list"
|
||||
end
|
||||
|
||||
create_table "audit_events", force: :cascade do |t|
|
||||
|
@ -854,6 +858,7 @@ ActiveRecord::Schema.define(version: 20160119112418) do
|
|||
t.boolean "hide_project_limit", default: false
|
||||
t.string "unlock_token"
|
||||
t.datetime "otp_grace_period_started_at"
|
||||
t.boolean "ldap_email", default: false, null: false
|
||||
end
|
||||
|
||||
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
|
||||
|
|
|
@ -17,6 +17,8 @@ DATABASE_URL | url | For example: postgresql://localhost/blog_development?pool=5
|
|||
GITLAB_EMAIL_FROM | email | Email address used in the "From" field in mails sent by GitLab
|
||||
GITLAB_EMAIL_DISPLAY_NAME | string | Name used in the "From" field in mails sent by GitLab
|
||||
GITLAB_EMAIL_REPLY_TO | email | Email address used in the "Reply-To" field in mails sent by GitLab
|
||||
GITLAB_UNICORN_MEMORY_MIN | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer
|
||||
GITLAB_UNICORN_MEMORY_MAX | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer
|
||||
|
||||
## Complete database variables
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ GET /groups/:id/projects
|
|||
Parameters:
|
||||
|
||||
- `archived` (optional) - if passed, limit by archived status
|
||||
- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
|
||||
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
|
||||
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
|
||||
- `search` (optional) - Return list of authorized projects according to a search criteria
|
||||
|
|
|
@ -29,6 +29,7 @@ GET /projects
|
|||
Parameters:
|
||||
|
||||
- `archived` (optional) - if passed, limit by archived status
|
||||
- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
|
||||
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
|
||||
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
|
||||
- `search` (optional) - Return list of authorized projects according to a search criteria
|
||||
|
@ -152,6 +153,7 @@ GET /projects/owned
|
|||
Parameters:
|
||||
|
||||
- `archived` (optional) - if passed, limit by archived status
|
||||
- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
|
||||
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
|
||||
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
|
||||
- `search` (optional) - Return list of authorized projects according to a search criteria
|
||||
|
@ -167,6 +169,7 @@ GET /projects/starred
|
|||
Parameters:
|
||||
|
||||
- `archived` (optional) - if passed, limit by archived status
|
||||
- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
|
||||
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
|
||||
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
|
||||
- `search` (optional) - Return list of authorized projects according to a search criteria
|
||||
|
@ -182,6 +185,7 @@ GET /projects/all
|
|||
Parameters:
|
||||
|
||||
- `archived` (optional) - if passed, limit by archived status
|
||||
- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
|
||||
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
|
||||
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
|
||||
- `search` (optional) - Return list of authorized projects according to a search criteria
|
||||
|
|
|
@ -56,7 +56,7 @@ export CI_SERVER_VERSION=""
|
|||
```
|
||||
|
||||
### YAML-defined variables
|
||||
**This feature requires GitLab Runner 0.5.0 or higher**
|
||||
**This feature requires GitLab Runner 0.5.0 or higher and GitLab CI 7.14 or higher **
|
||||
|
||||
GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build environment.
|
||||
The variables are stored in repository and are meant to store non-sensitive project configuration, ie. RAILS_ENV or DATABASE_URL.
|
||||
|
|
|
@ -56,7 +56,7 @@ X-Gitlab-Event: Push Hook
|
|||
"author": {
|
||||
"name": "Jordi Mallach",
|
||||
"email": "jordi@softcatala.org"
|
||||
}
|
||||
},
|
||||
"added": ["CHANGELOG"],
|
||||
"modified": ["app/controller/application.rb"],
|
||||
"removed": []
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Protected branches
|
||||
|
||||
Permission in GitLab are fundamentally defined around the idea of having read or write permission to the repository and branches.
|
||||
Permissions in GitLab are fundamentally defined around the idea of having read or write permission to the repository and branches.
|
||||
|
||||
To prevent people from messing with history or pushing code without review, we've created protected branches.
|
||||
|
||||
|
|
|
@ -51,6 +51,14 @@ Feature: Project Issues
|
|||
Then I should see comment "XML attached"
|
||||
And I should see an error alert section within the comment form
|
||||
|
||||
@javascript
|
||||
Scenario: Visiting Issues after leaving a comment
|
||||
Given I visit issue page "Release 0.4"
|
||||
And I leave a comment like "XML attached"
|
||||
And I visit project "Shop" issues page
|
||||
And I sort the list by "Last updated"
|
||||
Then I should see "Release 0.4" at the top
|
||||
|
||||
@javascript
|
||||
Scenario: I search issue
|
||||
Given I fill in issue search with "Re"
|
||||
|
|
|
@ -75,6 +75,25 @@ Feature: Project Merge Requests
|
|||
And I leave a comment like "XML attached"
|
||||
Then I should see comment "XML attached"
|
||||
|
||||
@javascript
|
||||
Scenario: Visiting Merge Requests after leaving a comment
|
||||
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
|
||||
And I visit merge request page "Bug NS-04"
|
||||
And I leave a comment like "XML attached"
|
||||
And I visit project "Shop" merge requests page
|
||||
And I sort the list by "Last updated"
|
||||
Then I should see "Bug NS-04" at the top
|
||||
|
||||
@javascript
|
||||
Scenario: Visiting Merge Requests after commenting on diffs
|
||||
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
|
||||
And I visit merge request page "Bug NS-05"
|
||||
And I click on the Changes tab
|
||||
And I leave a comment like "Line is wrong" on diff
|
||||
And I visit project "Shop" merge requests page
|
||||
And I sort the list by "Last updated"
|
||||
Then I should see "Bug NS-05" at the top
|
||||
|
||||
@javascript
|
||||
Scenario: I comment on a merge request diff
|
||||
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
|
||||
|
|
|
@ -293,6 +293,11 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
|
|||
expect(page).to have_content('Yay!')
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should see "Release 0.4" at the top' do
|
||||
expect(page.find('ul.content-list.issues-list li.issue:first-child')).to have_content("Release 0.4")
|
||||
end
|
||||
|
||||
def filter_issue(text)
|
||||
fill_in 'issue_search', with: text
|
||||
end
|
||||
|
|
|
@ -41,7 +41,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I should not see "master" branch' do
|
||||
expect(page).not_to have_content "master"
|
||||
expect(find('.merge-request-info')).not_to have_content "master"
|
||||
end
|
||||
|
||||
step 'I should see "other_branch" branch' do
|
||||
|
@ -440,6 +440,14 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
end
|
||||
end
|
||||
|
||||
step 'I should see "Bug NS-05" at the top' do
|
||||
expect(page.find('ul.content-list.mr-list li.merge-request:first-child')).to have_content("Bug NS-05")
|
||||
end
|
||||
|
||||
step 'I should see "Bug NS-04" at the top' do
|
||||
expect(page.find('ul.content-list.mr-list li.merge-request:first-child')).to have_content("Bug NS-04")
|
||||
end
|
||||
|
||||
def merge_request
|
||||
@merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
|
||||
end
|
||||
|
|
|
@ -144,4 +144,11 @@ module SharedNote
|
|||
expect(page).to have_content("+1 Awesome!")
|
||||
end
|
||||
end
|
||||
|
||||
step 'I sort the list by "Last updated"' do
|
||||
find('button.dropdown-toggle.btn').click
|
||||
page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
|
||||
click_link "Last updated"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -264,6 +264,10 @@ module API
|
|||
projects = projects.search(params[:search])
|
||||
end
|
||||
|
||||
if params[:visibility].present?
|
||||
projects = projects.search_by_visibility(params[:visibility])
|
||||
end
|
||||
|
||||
projects.reorder(project_order_by => project_sort)
|
||||
end
|
||||
|
||||
|
|
|
@ -133,6 +133,7 @@ module Banzai
|
|||
next unless link && text
|
||||
|
||||
link = CGI.unescape(link)
|
||||
next unless link.force_encoding('UTF-8').valid_encoding?
|
||||
# Ignore ending punctionation like periods or commas
|
||||
next unless link == text && text =~ /\A#{pattern}/
|
||||
|
||||
|
@ -170,6 +171,7 @@ module Banzai
|
|||
|
||||
next unless link && text
|
||||
link = CGI.unescape(link)
|
||||
next unless link.force_encoding('UTF-8').valid_encoding?
|
||||
next unless link && link =~ /\A#{pattern}\z/
|
||||
|
||||
html = yield link, text
|
||||
|
|
105
lib/dnsxl_check.rb
Normal file
105
lib/dnsxl_check.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
require 'resolv'
|
||||
|
||||
class DNSXLCheck
|
||||
|
||||
class Resolver
|
||||
def self.search(query)
|
||||
begin
|
||||
Resolv.getaddress(query)
|
||||
true
|
||||
rescue Resolv::ResolvError
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
IP_REGEXP = /\A(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\z/
|
||||
DEFAULT_THRESHOLD = 0.33
|
||||
|
||||
def self.create_from_list(list)
|
||||
dnsxl_check = DNSXLCheck.new
|
||||
|
||||
list.each do |entry|
|
||||
dnsxl_check.add_list(entry.domain, entry.weight)
|
||||
end
|
||||
|
||||
dnsxl_check
|
||||
end
|
||||
|
||||
def test(ip)
|
||||
if use_threshold?
|
||||
test_with_threshold(ip)
|
||||
else
|
||||
test_strict(ip)
|
||||
end
|
||||
end
|
||||
|
||||
def test_with_threshold(ip)
|
||||
return false if lists.empty?
|
||||
|
||||
search(ip)
|
||||
final_score >= threshold
|
||||
end
|
||||
|
||||
def test_strict(ip)
|
||||
return false if lists.empty?
|
||||
|
||||
search(ip)
|
||||
@score > 0
|
||||
end
|
||||
|
||||
def use_threshold=(value)
|
||||
@use_threshold = value == true
|
||||
end
|
||||
|
||||
def use_threshold?
|
||||
@use_threshold &&= true
|
||||
end
|
||||
|
||||
def threshold=(threshold)
|
||||
raise ArgumentError, "'threshold' value must be grather than 0 and less than or equal to 1" unless threshold > 0 && threshold <= 1
|
||||
@threshold = threshold
|
||||
end
|
||||
|
||||
def threshold
|
||||
@threshold ||= DEFAULT_THRESHOLD
|
||||
end
|
||||
|
||||
def add_list(domain, weight)
|
||||
@lists ||= []
|
||||
@lists << { domain: domain, weight: weight }
|
||||
end
|
||||
|
||||
def lists
|
||||
@lists ||= []
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def search(ip)
|
||||
raise ArgumentError, "'ip' value must be in #{IP_REGEXP} format" unless ip.match(IP_REGEXP)
|
||||
|
||||
@score = 0
|
||||
|
||||
reversed = reverse_ip(ip)
|
||||
search_in_rbls(reversed)
|
||||
end
|
||||
|
||||
def reverse_ip(ip)
|
||||
ip.split('.').reverse.join('.')
|
||||
end
|
||||
|
||||
def search_in_rbls(reversed_ip)
|
||||
lists.each do |rbl|
|
||||
query = "#{reversed_ip}.#{rbl[:domain]}"
|
||||
@score += rbl[:weight] if Resolver.search(query)
|
||||
end
|
||||
end
|
||||
|
||||
def final_score
|
||||
weights = lists.map{ |rbl| rbl[:weight] }.reduce(:+).to_i
|
||||
return 0 if weights == 0
|
||||
|
||||
(@score.to_f / weights.to_f).round(2)
|
||||
end
|
||||
end
|
|
@ -9,6 +9,7 @@ module Gitlab
|
|||
|
||||
delegate :namespace, :name_with_namespace, to: :project, prefix: :project
|
||||
delegate :name, to: :author, prefix: :author
|
||||
delegate :username, to: :author, prefix: :author
|
||||
|
||||
def initialize(notify, project_id, recipient, opts = {})
|
||||
raise ArgumentError, 'Missing options: author_id, ref, action' unless
|
||||
|
|
34
lib/gitlab/ip_check.rb
Normal file
34
lib/gitlab/ip_check.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
module Gitlab
|
||||
class IpCheck
|
||||
|
||||
def initialize(ip)
|
||||
@ip = ip
|
||||
|
||||
application_settings = ApplicationSetting.current
|
||||
@ip_blocking_enabled = application_settings.ip_blocking_enabled
|
||||
@dnsbl_servers_list = application_settings.dnsbl_servers_list
|
||||
end
|
||||
|
||||
def spam?
|
||||
@ip_blocking_enabled && blacklisted?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def blacklisted?
|
||||
on_dns_blacklist?
|
||||
end
|
||||
|
||||
def on_dns_blacklist?
|
||||
dnsbl_check = DNSXLCheck.new
|
||||
prepare_dnsbl_list(dnsbl_check)
|
||||
dnsbl_check.test(@ip)
|
||||
end
|
||||
|
||||
def prepare_dnsbl_list(dnsbl_check)
|
||||
@dnsbl_servers_list.split(',').map(&:strip).reject(&:empty?).each do |domain|
|
||||
dnsbl_check.add_list(domain, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,28 +30,31 @@ module Gitlab
|
|||
end
|
||||
|
||||
def find_by_uid_and_provider
|
||||
self.class.find_by_uid_and_provider(
|
||||
auth_hash.uid, auth_hash.provider)
|
||||
self.class.find_by_uid_and_provider(auth_hash.uid, auth_hash.provider)
|
||||
end
|
||||
|
||||
def find_by_email
|
||||
::User.find_by(email: auth_hash.email.downcase)
|
||||
::User.find_by(email: auth_hash.email.downcase) if auth_hash.has_email?
|
||||
end
|
||||
|
||||
def update_user_attributes
|
||||
return unless persisted?
|
||||
if persisted?
|
||||
if auth_hash.has_email?
|
||||
gl_user.skip_reconfirmation!
|
||||
gl_user.email = auth_hash.email
|
||||
end
|
||||
|
||||
gl_user.skip_reconfirmation!
|
||||
gl_user.email = auth_hash.email
|
||||
# find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
|
||||
identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
|
||||
identity ||= gl_user.identities.build(provider: auth_hash.provider)
|
||||
|
||||
# find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
|
||||
identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
|
||||
identity ||= gl_user.identities.build(provider: auth_hash.provider)
|
||||
# For a new identity set extern_uid to the LDAP DN
|
||||
# For an existing identity with matching email but changed DN, update the DN.
|
||||
# For an existing identity with no change in DN, this line changes nothing.
|
||||
identity.extern_uid = auth_hash.uid
|
||||
end
|
||||
|
||||
# For a new user set extern_uid to the LDAP DN
|
||||
# For an existing user with matching email but changed DN, update the DN.
|
||||
# For an existing user with no change in DN, this line changes nothing.
|
||||
identity.extern_uid = auth_hash.uid
|
||||
gl_user.ldap_email = auth_hash.has_email?
|
||||
|
||||
gl_user
|
||||
end
|
||||
|
|
|
@ -32,6 +32,10 @@ module Gitlab
|
|||
@password ||= Gitlab::Utils.force_utf8(Devise.friendly_token[0, 8].downcase)
|
||||
end
|
||||
|
||||
def has_email?
|
||||
get_info(:email).present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def info
|
||||
|
@ -46,8 +50,8 @@ module Gitlab
|
|||
|
||||
def username_and_email
|
||||
@username_and_email ||= begin
|
||||
username = get_info(:username) || get_info(:nickname)
|
||||
email = get_info(:email)
|
||||
username = get_info(:username).presence || get_info(:nickname).presence
|
||||
email = get_info(:email).presence
|
||||
|
||||
username ||= generate_username(email) if email
|
||||
email ||= generate_temporarily_email(username) if username
|
||||
|
|
|
@ -111,7 +111,7 @@ module Gitlab
|
|||
def block_after_signup?
|
||||
if creating_linked_ldap_user?
|
||||
ldap_config.block_auto_created_users
|
||||
else
|
||||
else
|
||||
Gitlab.config.omniauth.block_auto_created_users
|
||||
end
|
||||
end
|
||||
|
@ -135,16 +135,16 @@ module Gitlab
|
|||
def user_attributes
|
||||
# Give preference to LDAP for sensitive information when creating a linked account
|
||||
if creating_linked_ldap_user?
|
||||
username = ldap_person.username
|
||||
email = ldap_person.email.first
|
||||
else
|
||||
username = auth_hash.username
|
||||
email = auth_hash.email
|
||||
username = ldap_person.username.presence
|
||||
email = ldap_person.email.first.presence
|
||||
end
|
||||
|
||||
username ||= auth_hash.username
|
||||
email ||= auth_hash.email
|
||||
|
||||
name = auth_hash.name
|
||||
name = ::Namespace.clean_path(username) if name.strip.empty?
|
||||
|
||||
|
||||
{
|
||||
name: name,
|
||||
username: ::Namespace.clean_path(username),
|
||||
|
|
68
spec/lib/dnsxl_check_spec.rb
Normal file
68
spec/lib/dnsxl_check_spec.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
require 'spec_helper'
|
||||
require 'ostruct'
|
||||
|
||||
describe 'DNSXLCheck', lib: true, no_db: true do
|
||||
let(:spam_ip) { '127.0.0.2' }
|
||||
let(:no_spam_ip) { '127.0.0.3' }
|
||||
let(:invalid_ip) { 'a.b.c.d' }
|
||||
let!(:dnsxl_check) { DNSXLCheck.create_from_list([OpenStruct.new({ domain: 'test', weight: 1 })]) }
|
||||
|
||||
before(:context) do
|
||||
class DNSXLCheck::Resolver
|
||||
class << self
|
||||
alias_method :old_search, :search
|
||||
def search(query)
|
||||
return false if query.match(/always\.failing\.domain\z/)
|
||||
return true if query.match(/\A2\.0\.0\.127\./)
|
||||
return false if query.match(/\A3\.0\.0\.127\./)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#test' do
|
||||
before do
|
||||
dnsxl_check.threshold = 0.75
|
||||
dnsxl_check.add_list('always.failing.domain', 1)
|
||||
end
|
||||
|
||||
context 'when threshold is used' do
|
||||
before { dnsxl_check.use_threshold= true }
|
||||
|
||||
it { expect(dnsxl_check.test(spam_ip)).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when threshold is not used' do
|
||||
before { dnsxl_check.use_threshold= false }
|
||||
|
||||
it { expect(dnsxl_check.test(spam_ip)).to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#test_with_threshold' do
|
||||
it { expect{ dnsxl_check.test_with_threshold(invalid_ip) }.to raise_error(ArgumentError) }
|
||||
|
||||
it { expect(dnsxl_check.test_with_threshold(spam_ip)).to be_truthy }
|
||||
it { expect(dnsxl_check.test_with_threshold(no_spam_ip)).to be_falsey }
|
||||
end
|
||||
|
||||
describe '#test_strict' do
|
||||
before do
|
||||
dnsxl_check.threshold = 1
|
||||
dnsxl_check.add_list('always.failing.domain', 1)
|
||||
end
|
||||
|
||||
it { expect{ dnsxl_check.test_strict(invalid_ip) }.to raise_error(ArgumentError) }
|
||||
|
||||
it { expect(dnsxl_check.test_with_threshold(spam_ip)).to be_falsey }
|
||||
it { expect(dnsxl_check.test_with_threshold(no_spam_ip)).to be_falsey }
|
||||
it { expect(dnsxl_check.test_strict(spam_ip)).to be_truthy }
|
||||
it { expect(dnsxl_check.test_strict(no_spam_ip)).to be_falsey }
|
||||
end
|
||||
|
||||
describe '#threshold=' do
|
||||
it { expect{ dnsxl_check.threshold = 0 }.to raise_error(ArgumentError) }
|
||||
it { expect{ dnsxl_check.threshold = 1.1 }.to raise_error(ArgumentError) }
|
||||
it { expect{ dnsxl_check.threshold = 0.5 }.not_to raise_error }
|
||||
end
|
||||
end
|
|
@ -37,7 +37,7 @@ describe Gitlab::LDAP::User, lib: true do
|
|||
end
|
||||
|
||||
it "dont marks existing ldap user as changed" do
|
||||
create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
|
||||
create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', ldap_email: true)
|
||||
expect(ldap_user.changed?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
@ -110,6 +110,32 @@ describe Gitlab::LDAP::User, lib: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'updating email' do
|
||||
context "when LDAP sets an email" do
|
||||
it "has a real email" do
|
||||
expect(ldap_user.gl_user.email).to eq(info[:email])
|
||||
end
|
||||
|
||||
it "has ldap_email set to true" do
|
||||
expect(ldap_user.gl_user.ldap_email?).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context "when LDAP doesn't set an email" do
|
||||
before do
|
||||
info.delete(:email)
|
||||
end
|
||||
|
||||
it "has a temp email" do
|
||||
expect(ldap_user.gl_user.temp_oauth_email?).to be(true)
|
||||
end
|
||||
|
||||
it "has ldap_email set to false" do
|
||||
expect(ldap_user.gl_user.ldap_email?).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'blocking' do
|
||||
def configure_block(value)
|
||||
allow_any_instance_of(Gitlab::LDAP::Config).
|
||||
|
|
|
@ -37,7 +37,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
|
|||
|
||||
it 'returns the note and issue-specific data' do
|
||||
expect(data).to have_key(:issue)
|
||||
expect(data[:issue]).to eq(issue.hook_attrs)
|
||||
expect(data[:issue].except('updated_at')).to eq(issue.hook_attrs.except('updated_at'))
|
||||
expect(data[:issue]['updated_at']).to be > issue.hook_attrs['updated_at']
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -47,7 +48,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
|
|||
|
||||
it 'returns the note and merge request data' do
|
||||
expect(data).to have_key(:merge_request)
|
||||
expect(data[:merge_request]).to eq(merge_request.hook_attrs)
|
||||
expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at'))
|
||||
expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at']
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -57,7 +59,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
|
|||
|
||||
it 'returns the note and merge request diff data' do
|
||||
expect(data).to have_key(:merge_request)
|
||||
expect(data[:merge_request]).to eq(merge_request.hook_attrs)
|
||||
expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at'))
|
||||
expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at']
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -67,7 +70,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
|
|||
|
||||
it 'returns the note and project snippet data' do
|
||||
expect(data).to have_key(:snippet)
|
||||
expect(data[:snippet]).to eq(snippet.hook_attrs)
|
||||
expect(data[:snippet].except('updated_at')).to eq(snippet.hook_attrs.except('updated_at'))
|
||||
expect(data[:snippet]['updated_at']).to be > snippet.hook_attrs['updated_at']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,14 +40,38 @@ describe Notify do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'an email with X-GitLab headers containing project details' do
|
||||
it 'has X-GitLab-Project* headers' do
|
||||
is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
|
||||
is_expected.to have_header 'X-GitLab-Project-Id', /#{project.id}/
|
||||
is_expected.to have_header 'X-GitLab-Project-Path', /#{project.path_with_namespace}/
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an email with X-GitLab headers containing build details' do
|
||||
it 'has X-GitLab-Build* headers' do
|
||||
is_expected.to have_header 'X-GitLab-Build-Id', /#{build.id}/
|
||||
is_expected.to have_header 'X-GitLab-Build-Ref', /#{build.ref}/
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an email that contains a header with author username' do
|
||||
it 'has X-GitLab-Author header containing author\'s username' do
|
||||
is_expected.to have_header 'X-GitLab-Author', user.username
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an email starting a new thread' do |message_id_prefix|
|
||||
include_examples 'an email with X-GitLab headers containing project details'
|
||||
|
||||
it 'has a discussion identifier' do
|
||||
is_expected.to have_header 'Message-ID', /<#{message_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
|
||||
is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an answer to an existing thread' do |thread_id_prefix|
|
||||
include_examples 'an email with X-GitLab headers containing project details'
|
||||
|
||||
it 'has a subject that begins with Re: ' do
|
||||
is_expected.to have_subject /^Re: /
|
||||
end
|
||||
|
@ -56,7 +80,6 @@ describe Notify do
|
|||
is_expected.to have_header 'Message-ID', /<(.*)@#{Gitlab.config.gitlab.host}>/
|
||||
is_expected.to have_header 'References', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
|
||||
is_expected.to have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
|
||||
is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -656,6 +679,8 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details'
|
||||
it_behaves_like 'an email that contains a header with author username'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -685,6 +710,8 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details'
|
||||
it_behaves_like 'an email that contains a header with author username'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -713,6 +740,8 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details'
|
||||
it_behaves_like 'an email that contains a header with author username'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -737,6 +766,8 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details'
|
||||
it_behaves_like 'an email that contains a header with author username'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -765,6 +796,8 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details'
|
||||
it_behaves_like 'an email that contains a header with author username'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -871,6 +904,8 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'it should show Gmail Actions View Commit link'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details'
|
||||
it_behaves_like 'an email that contains a header with author username'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -904,6 +939,15 @@ describe Notify do
|
|||
|
||||
subject { Notify.build_success_email(build.id, 'wow@example.com') }
|
||||
|
||||
it_behaves_like 'an email with X-GitLab headers containing build details'
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details' do
|
||||
let(:project) { build.project }
|
||||
end
|
||||
|
||||
it 'has header indicating build status' do
|
||||
is_expected.to have_header 'X-GitLab-Build-Status', 'success'
|
||||
end
|
||||
|
||||
it 'has the correct subject' do
|
||||
should have_subject /Build success for/
|
||||
end
|
||||
|
@ -918,6 +962,15 @@ describe Notify do
|
|||
|
||||
subject { Notify.build_fail_email(build.id, 'wow@example.com') }
|
||||
|
||||
it_behaves_like 'an email with X-GitLab headers containing build details'
|
||||
it_behaves_like 'an email with X-GitLab headers containing project details' do
|
||||
let(:project) { build.project }
|
||||
end
|
||||
|
||||
it 'has header indicating build status' do
|
||||
is_expected.to have_header 'X-GitLab-Build-Status', 'failed'
|
||||
end
|
||||
|
||||
it 'has the correct subject' do
|
||||
should have_subject /Build failed for/
|
||||
end
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
# recaptcha_site_key :string
|
||||
# recaptcha_private_key :string
|
||||
# metrics_port :integer default(8089)
|
||||
# sentry_enabled :boolean default(FALSE)
|
||||
# sentry_dsn :string
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
|
|
@ -90,6 +90,29 @@ describe API::API, api: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'and using the visibility filter' do
|
||||
it 'should filter based on private visibility param' do
|
||||
get api('/projects', user), { visibility: 'private' }
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).count)
|
||||
end
|
||||
|
||||
it 'should filter based on internal visibility param' do
|
||||
get api('/projects', user), { visibility: 'internal' }
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).count)
|
||||
end
|
||||
|
||||
it 'should filter based on public visibility param' do
|
||||
get api('/projects', user), { visibility: 'public' }
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and using sorting' do
|
||||
before do
|
||||
project2
|
||||
|
|
Loading…
Reference in a new issue