diff options
author | Rémy Coutable <remy@rymai.me> | 2016-01-20 22:42:07 +0100 |
---|---|---|
committer | Rémy Coutable <remy@rymai.me> | 2016-01-20 22:42:07 +0100 |
commit | 8a829c9738f2d4275b9233a722ffaa2cbb145553 (patch) | |
tree | b62b75f14e1603e2a7cd45a4e82dc4886d882467 | |
parent | 12da27090f0a8ff4b05023a5216738413dcbe110 (diff) | |
parent | 714f95b2ff68c02eeee9151c9b456bb2afe7eaff (diff) | |
download | gitlab-ce-8a829c9738f2d4275b9233a722ffaa2cbb145553.tar.gz |
Merge remote-tracking branch 'origin/master' into fix-comment-on-diff-ajax-loading
59 files changed, 634 insertions, 76 deletions
diff --git a/CHANGELOG b/CHANGELOG index 1fbabd1b77b..981581342bc 100644 --- a/CHANGELOG +++ b/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) @@ -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' diff --git a/Gemfile.lock b/Gemfile.lock index a14fdbeed23..5e0718af70f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index 9d5ae6c04e9..1ef31c7700e 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -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) -> diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 58d6b9d4060..0d88e8d254a 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -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' diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index 4d915bfc8c5..f141fb69c3e 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -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) diff --git a/app/assets/javascripts/shortcuts_tree.coffee b/app/assets/javascripts/shortcuts_tree.coffee deleted file mode 100644 index ba0839c9fc0..00000000000 --- a/app/assets/javascripts/shortcuts_tree.coffee +++ /dev/null @@ -1,4 +0,0 @@ -class @ShortcutsTree extends ShortcutsNavigation - constructor: -> - super() - Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file')) diff --git a/app/assets/javascripts/star.js.coffee b/app/assets/javascripts/star.js.coffee index d849b2e7950..f27780dda93 100644 --- a/app/assets/javascripts/star.js.coffee +++ b/app/assets/javascripts/star.js.coffee @@ -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
\ No newline at end of file + return diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 85ecdddda79..3ec48da9a41 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -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 diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 3a87b71078d..003a4c22f20 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -558,3 +558,9 @@ pre.light-well { width: 101%; } } + +.cannot-be-merged, +.cannot-be-merged:hover { + color: #E62958; + margin-top: 2px; +} diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 91f7d78bd73..094eef28a43 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -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: [] ) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bf99b2e777d..633c3f55614 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -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! diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index c48175a4c5a..5efdd613e79 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -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." diff --git a/app/mailers/emails/builds.rb b/app/mailers/emails/builds.rb index d58609a2de5..64c1ce8cfab 100644 --- a/app/mailers/emails/builds.rb +++ b/app/mailers/emails/builds.rb @@ -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 diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index b96418679bd..377c2999d6c 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -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, diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index e1cd075a978..8cbc9eefc7b 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -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 diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 6c6c2468374..2f3487b53ac 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -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| diff --git a/app/models/note.rb b/app/models/note.rb index 3e1375e5ad6..15f48110ad2 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -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" diff --git a/app/models/project.rb b/app/models/project.rb index cb668e0c2f7..5579710a476 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index 592468933ed..4214f01f6a4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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 diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 83f6814d822..c4020c8273b 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -215,6 +215,22 @@ .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 = f.label :recaptcha_enabled do = f.check_box :recaptcha_enabled Enable reCAPTCHA @@ -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' diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 3892ef8eefa..fcb6b835a7e 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -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)}";
\ No newline at end of file diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 9459d8a6295..add9a00138b 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -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 diff --git a/app/views/projects/artifacts/_tree_directory.html.haml b/app/views/projects/artifacts/_tree_directory.html.haml index e4b7979949c..def493c56f5 100644 --- a/app/views/projects/artifacts/_tree_directory.html.haml +++ b/app/views/projects/artifacts/_tree_directory.html.haml @@ -6,4 +6,3 @@ %span.str-truncated = link_to directory.name, path_to_directory %td - %td diff --git a/app/views/projects/artifacts/_tree_file.html.haml b/app/views/projects/artifacts/_tree_file.html.haml index 3dfc09cc495..36fb4c998c9 100644 --- a/app/views/projects/artifacts/_tree_file.html.haml +++ b/app/views/projects/artifacts/_tree_file.html.haml @@ -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) diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml index b70c776a2b2..d3c969cc035 100644 --- a/app/views/projects/artifacts/browse.html.haml +++ b/app/views/projects/artifacts/browse.html.haml @@ -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 diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index 40a2a61d8a1..905f6bbbd48 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -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 diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 9f4a7098ea2..3092ff54242 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -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 diff --git a/config.ru b/config.ru index a2525c81361..065ce59932f 100644 --- a/config.ru +++ b/config.ru @@ -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 diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb new file mode 100644 index 00000000000..d0630b9fa07 --- /dev/null +++ b/config/initializers/sentry.rb @@ -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 diff --git a/db/migrate/20160118155830_add_sentry_to_application_settings.rb b/db/migrate/20160118155830_add_sentry_to_application_settings.rb new file mode 100644 index 00000000000..fa7ff9d9228 --- /dev/null +++ b/db/migrate/20160118155830_add_sentry_to_application_settings.rb @@ -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 diff --git a/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb b/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb new file mode 100644 index 00000000000..26606b10b54 --- /dev/null +++ b/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb @@ -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 diff --git a/db/migrate/20160119145451_add_ldap_email_to_users.rb b/db/migrate/20160119145451_add_ldap_email_to_users.rb new file mode 100644 index 00000000000..654d31ab15a --- /dev/null +++ b/db/migrate/20160119145451_add_ldap_email_to_users.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index a08181b910f..50ae69bdd0f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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 diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md index 1eb3a74d304..42a27dcf6d6 100644 --- a/doc/administration/environment_variables.md +++ b/doc/administration/environment_variables.md @@ -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 diff --git a/doc/api/groups.md b/doc/api/groups.md index 808675d8605..d47e79ba47f 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -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
diff --git a/doc/api/projects.md b/doc/api/projects.md index 241229221db..3f372c955d2 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -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 diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index b99ea25a3fe..862cacda586 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -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. diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md index 6420d65cf1b..c29037e89c2 100644 --- a/doc/web_hooks/web_hooks.md +++ b/doc/web_hooks/web_hooks.md @@ -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": [] diff --git a/doc/workflow/protected_branches.md b/doc/workflow/protected_branches.md index 0adf9f8e3e8..fdf9a8d391c 100644 --- a/doc/workflow/protected_branches.md +++ b/doc/workflow/protected_branches.md @@ -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. diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index ab234bc7507..1502b0952cd 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -52,6 +52,14 @@ Feature: Project Issues 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" Then I should see "Release 0.4" in issues diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 1be5ddcd7e4..4f780aa680f 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -76,6 +76,25 @@ Feature: Project Merge Requests 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 And I visit merge request page "Bug NS-05" diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index 8e8c9c57452..d556b73f9fd 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -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 diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index c0b9984997c..337893e6209 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -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 diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index 444d6726f99..eb6df61b8e6 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -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 diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 6d2380cf47d..3f528b9f7c0 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -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 diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb index 20bd4f7ee6e..3637b1bac94 100644 --- a/lib/banzai/filter/reference_filter.rb +++ b/lib/banzai/filter/reference_filter.rb @@ -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 diff --git a/lib/dnsxl_check.rb b/lib/dnsxl_check.rb new file mode 100644 index 00000000000..1e506b2d9cb --- /dev/null +++ b/lib/dnsxl_check.rb @@ -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 diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index a2eb7a70bd2..a05ffeb9cd2 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -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 diff --git a/lib/gitlab/ip_check.rb b/lib/gitlab/ip_check.rb new file mode 100644 index 00000000000..f2e9b50d225 --- /dev/null +++ b/lib/gitlab/ip_check.rb @@ -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 diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb index aef08c97d1d..e044f0ecc6d 100644 --- a/lib/gitlab/ldap/user.rb +++ b/lib/gitlab/ldap/user.rb @@ -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 diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb index ba31599432b..36e5c2670bb 100644 --- a/lib/gitlab/o_auth/auth_hash.rb +++ b/lib/gitlab/o_auth/auth_hash.rb @@ -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 diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb index e3d2cc65a8f..d87a72f7ba3 100644 --- a/lib/gitlab/o_auth/user.rb +++ b/lib/gitlab/o_auth/user.rb @@ -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), diff --git a/spec/lib/dnsxl_check_spec.rb b/spec/lib/dnsxl_check_spec.rb new file mode 100644 index 00000000000..a35a1be0c90 --- /dev/null +++ b/spec/lib/dnsxl_check_spec.rb @@ -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 diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index 1e755259dae..03199a2523e 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -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). diff --git a/spec/lib/gitlab/note_data_builder_spec.rb b/spec/lib/gitlab/note_data_builder_spec.rb index 6cbdae737f4..691f36e6cb7 100644 --- a/spec/lib/gitlab/note_data_builder_spec.rb +++ b/spec/lib/gitlab/note_data_builder_spec.rb @@ -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 diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 8f86c491d3f..7289e596ef3 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -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 diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 91b250265e6..f4c58882757 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -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' diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6f4c336b66c..2a310f3834d 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -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 |