mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-21 10:36:04 +10:00
Merge branch 'master' of https://gitlab.com/gitlab-org/gitlab-ce into sentry-integration
Conflicts: db/schema.rb
This commit is contained in:
+2
-2
@@ -8,7 +8,7 @@ before_script:
|
||||
- touch log/application.log
|
||||
- touch log/test.log
|
||||
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"
|
||||
- bundle exec rake db:reset db:create RAILS_ENV=test
|
||||
- RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate
|
||||
|
||||
spec:feature:
|
||||
script:
|
||||
@@ -118,7 +118,7 @@ flay:
|
||||
- mysql
|
||||
|
||||
bundler:audit:
|
||||
script:
|
||||
script:
|
||||
- "bundle exec bundle-audit update"
|
||||
- "bundle exec bundle-audit check"
|
||||
tags:
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
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
|
||||
|
||||
v 8.4.0 (unreleased)
|
||||
- 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
|
||||
- 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
|
||||
@@ -57,11 +63,17 @@ 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)
|
||||
|
||||
v 8.3.4
|
||||
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
|
||||
- Add build artifacts browser
|
||||
|
||||
v 8.3.3
|
||||
- Preserve CE behavior with JIRA integration by only calling API if URL is set
|
||||
@@ -109,6 +121,7 @@ v 8.3.0
|
||||
- Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera)
|
||||
- Add rake tasks for git repository maintainance (Zeger-Jan van de Weg)
|
||||
- Fix 500 error when update group member permission
|
||||
- Fix: As an admin, cannot add oneself as a member to a group/project
|
||||
- Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
|
||||
- Recognize issue/MR/snippet/commit links as references
|
||||
- Backport JIRA features from EE to CE
|
||||
@@ -170,7 +183,6 @@ v 8.2.2
|
||||
- Fix Error 500 when viewing user's personal projects from admin page (Stan Hu)
|
||||
- Fix: Raw private snippets access workflow
|
||||
- Prevent "413 Request entity too large" errors when pushing large files with LFS
|
||||
- Fix: As an admin, cannot add oneself as a member to a group/project
|
||||
- Fix invalid links within projects dashboard header
|
||||
- Make current user the first user in assignee dropdown in issues detail page (Stan Hu)
|
||||
- Fix: duplicate email notifications on issue comments
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.5.4
|
||||
0.6.0
|
||||
|
||||
@@ -18,7 +18,7 @@ gem "mysql2", '~> 0.3.16', group: :mysql
|
||||
gem "pg", '~> 0.18.2', group: :postgres
|
||||
|
||||
# Authentication libraries
|
||||
gem 'devise', '~> 3.5.3'
|
||||
gem 'devise', '~> 3.5.4'
|
||||
gem 'devise-async', '~> 0.9.0'
|
||||
gem 'doorkeeper', '~> 2.2.0'
|
||||
gem 'omniauth', '~> 1.2.2'
|
||||
|
||||
+5
-5
@@ -157,7 +157,7 @@ GEM
|
||||
activerecord (>= 3.2.0, < 5.0)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
devise (3.5.3)
|
||||
devise (3.5.4)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 3.2.6, < 5)
|
||||
@@ -614,7 +614,7 @@ GEM
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.0.0)
|
||||
raindrops (0.15.0)
|
||||
rake (10.4.2)
|
||||
rake (10.5.0)
|
||||
raphael-rails (2.1.2)
|
||||
rb-fsevent (0.9.6)
|
||||
rb-inotify (0.9.5)
|
||||
@@ -648,8 +648,8 @@ GEM
|
||||
request_store (1.2.1)
|
||||
rerun (0.11.0)
|
||||
listen (~> 3.0)
|
||||
responders (2.1.0)
|
||||
railties (>= 4.2.0, < 5)
|
||||
responders (2.1.1)
|
||||
railties (>= 4.2.0, < 5.1)
|
||||
rest-client (1.8.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 3.0)
|
||||
@@ -913,7 +913,7 @@ DEPENDENCIES
|
||||
d3_rails (~> 3.5.0)
|
||||
database_cleaner (~> 1.4.0)
|
||||
default_value_for (~> 3.0.0)
|
||||
devise (~> 3.5.3)
|
||||
devise (~> 3.5.4)
|
||||
devise-async (~> 0.9.0)
|
||||
devise-two-factor (~> 2.0.0)
|
||||
diffy (~> 3.0.3)
|
||||
|
||||
@@ -19,7 +19,7 @@ class @AwardsHandler
|
||||
@addAwardToEmojiBar(emoji)
|
||||
|
||||
$(".emoji-menu").hide()
|
||||
|
||||
|
||||
addAwardToEmojiBar: (emoji) ->
|
||||
@addEmojiToFrequentlyUsedList(emoji)
|
||||
|
||||
@@ -66,9 +66,14 @@ class @AwardsHandler
|
||||
|
||||
addMeToAuthorList: (emoji) ->
|
||||
award_block = @findEmojiIcon(emoji).parent()
|
||||
authors = award_block.attr("data-original-title").split(", ")
|
||||
authors = _.compact(award_block.attr("data-original-title").split(", "))
|
||||
authors.push("me")
|
||||
award_block.attr("title", authors.join(", "))
|
||||
|
||||
if authors.length == 1
|
||||
award_block.attr("title", "me")
|
||||
else
|
||||
award_block.attr("title", authors.join(", "))
|
||||
|
||||
@resetTooltip(award_block)
|
||||
|
||||
resetTooltip: (award) ->
|
||||
@@ -78,7 +83,7 @@ class @AwardsHandler
|
||||
setTimeout (->
|
||||
award.tooltip()
|
||||
), 200
|
||||
|
||||
|
||||
|
||||
createEmoji: (emoji) ->
|
||||
emojiCssClass = @resolveNameToCssClass(emoji)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.filter-item {
|
||||
margin-right: 15px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -36,6 +36,10 @@ li.commit {
|
||||
line-height: 20px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
.btn-clipboard {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.notes_count {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
|
||||
@@ -558,3 +558,9 @@ pre.light-well {
|
||||
width: 101%;
|
||||
}
|
||||
}
|
||||
|
||||
.cannot-be-merged,
|
||||
.cannot-be-merged:hover {
|
||||
color: #E62958;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
border-bottom: 1px solid #DDD;
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.term {
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -468,12 +472,9 @@ class Project < ActiveRecord::Base
|
||||
!external_issue_tracker
|
||||
end
|
||||
|
||||
def external_issues_trackers
|
||||
services.select(&:issue_tracker?).reject(&:default?)
|
||||
end
|
||||
|
||||
def external_issue_tracker
|
||||
@external_issues_tracker ||= external_issues_trackers.find(&:activated?)
|
||||
@external_issue_tracker ||=
|
||||
services.issue_trackers.active.without_defaults.first
|
||||
end
|
||||
|
||||
def can_have_issues_tracker_id?
|
||||
|
||||
@@ -23,14 +23,12 @@
|
||||
# List methods you need to implement to get your CI service
|
||||
# working with GitLab Merge Requests
|
||||
class CiService < Service
|
||||
def category
|
||||
:ci
|
||||
end
|
||||
|
||||
default_value_for :category, 'ci'
|
||||
|
||||
def valid_token?(token)
|
||||
self.respond_to?(:token) && self.token.present? && self.token == token
|
||||
end
|
||||
|
||||
|
||||
def supported_events
|
||||
%w(push)
|
||||
end
|
||||
|
||||
@@ -24,9 +24,7 @@ class GitlabIssueTrackerService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def default?
|
||||
true
|
||||
end
|
||||
default_value_for :default, true
|
||||
|
||||
def to_param
|
||||
'gitlab'
|
||||
|
||||
@@ -23,12 +23,10 @@ class IssueTrackerService < Service
|
||||
|
||||
validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
|
||||
|
||||
def category
|
||||
:issue_tracker
|
||||
end
|
||||
default_value_for :category, 'issue_tracker'
|
||||
|
||||
def default?
|
||||
false
|
||||
default
|
||||
end
|
||||
|
||||
def issue_url(iid)
|
||||
|
||||
@@ -43,6 +43,9 @@ class Service < ActiveRecord::Base
|
||||
validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
|
||||
|
||||
scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) }
|
||||
scope :issue_trackers, -> { where(category: 'issue_tracker') }
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :without_defaults, -> { where(default: false) }
|
||||
|
||||
scope :push_hooks, -> { where(push_events: true, active: true) }
|
||||
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
|
||||
@@ -51,6 +54,8 @@ class Service < ActiveRecord::Base
|
||||
scope :note_hooks, -> { where(note_events: true, active: true) }
|
||||
scope :build_hooks, -> { where(build_events: true, active: true) }
|
||||
|
||||
default_value_for :category, 'common'
|
||||
|
||||
def activated?
|
||||
active
|
||||
end
|
||||
@@ -60,7 +65,7 @@ class Service < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def category
|
||||
:common
|
||||
read_attribute(:category).to_sym
|
||||
end
|
||||
|
||||
def initialize_properties
|
||||
@@ -153,7 +158,7 @@ class Service < ActiveRecord::Base
|
||||
|
||||
# Returns a hash of the properties that have been assigned a new value since last save,
|
||||
# indicating their original values (attr => original value).
|
||||
# ActiveRecord does not provide a mechanism to track changes in serialized keys,
|
||||
# ActiveRecord does not provide a mechanism to track changes in serialized keys,
|
||||
# so we need a specific implementation for service properties.
|
||||
# This allows to track changes to properties set with the accessor methods,
|
||||
# but not direct manipulation of properties hash.
|
||||
@@ -164,7 +169,7 @@ class Service < ActiveRecord::Base
|
||||
def reset_updated_properties
|
||||
@updated_properties = nil
|
||||
end
|
||||
|
||||
|
||||
def async_execute(data)
|
||||
return unless supported_events.include?(data[:object_kind])
|
||||
|
||||
|
||||
+4
-1
@@ -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
|
||||
|
||||
@@ -376,10 +376,10 @@ class NotificationService
|
||||
end
|
||||
|
||||
def reassign_resource_email(target, project, current_user, method)
|
||||
previous_assignee_id = previous_record(target, "assignee_id")
|
||||
previous_assignee_id = previous_record(target, 'assignee_id')
|
||||
previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
|
||||
|
||||
recipients = build_recipients(target, project, current_user, [previous_assignee])
|
||||
recipients = build_recipients(target, project, current_user, action: :reassign, previous_assignee: previous_assignee)
|
||||
|
||||
recipients.each do |recipient|
|
||||
mailer.send(
|
||||
@@ -400,22 +400,27 @@ class NotificationService
|
||||
end
|
||||
end
|
||||
|
||||
def build_recipients(target, project, current_user, extra_recipients = nil)
|
||||
def build_recipients(target, project, current_user, action: nil, previous_assignee: nil)
|
||||
recipients = target.participants(current_user)
|
||||
|
||||
recipients = recipients.concat(extra_recipients).compact.uniq if extra_recipients
|
||||
|
||||
recipients = add_project_watchers(recipients, project)
|
||||
recipients = reject_mention_users(recipients, project)
|
||||
recipients = reject_muted_users(recipients, project)
|
||||
|
||||
# Re-assign is considered as a mention of the new assignee so we add the
|
||||
# new assignee to the list of recipients after we rejected users with
|
||||
# the "on mention" notification level
|
||||
if action == :reassign
|
||||
recipients << previous_assignee if previous_assignee
|
||||
recipients << target.assignee
|
||||
end
|
||||
|
||||
recipients = reject_muted_users(recipients, project)
|
||||
recipients = add_subscribed_users(recipients, target)
|
||||
recipients = reject_unsubscribed_users(recipients, target)
|
||||
|
||||
recipients.delete(current_user)
|
||||
recipients = recipients.uniq
|
||||
|
||||
recipients
|
||||
recipients.uniq
|
||||
end
|
||||
|
||||
def mailer
|
||||
|
||||
@@ -95,7 +95,7 @@ module Projects
|
||||
system_hook_service.execute_hooks_for(@project, :create)
|
||||
|
||||
unless @project.group
|
||||
@project.team << [current_user, :master, current_user]
|
||||
@project.team << [current_user, :master]
|
||||
end
|
||||
|
||||
@project.import_start if @project.import?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
%tr{ class: 'tree-item' }
|
||||
- path_to_directory = browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build, path: directory.path)
|
||||
|
||||
%tr.tree-item{ 'data-link' => path_to_directory}
|
||||
%td.tree-item-file-name
|
||||
= tree_icon('folder', '755', directory.name)
|
||||
%span.str-truncated
|
||||
= link_to directory.name, browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build, path: directory.path)
|
||||
= link_to directory.name, path_to_directory
|
||||
%td
|
||||
%td
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
%tr{ class: 'tree-item' }
|
||||
- path_to_file = file_namespace_project_build_artifacts_path(@project.namespace, @project, @build, path: file.path)
|
||||
|
||||
%tr.tree-item{ 'data-link' => path_to_file }
|
||||
%td.tree-item-file-name
|
||||
= tree_icon('file', '664', file.name)
|
||||
%span.str-truncated
|
||||
= file.name
|
||||
= link_to file.name, path_to_file
|
||||
%td
|
||||
= number_to_human_size(file.metadata[:size], precision: 2)
|
||||
%td
|
||||
= link_to file_namespace_project_build_artifacts_path(@project.namespace, @project, @build, path: file.path),
|
||||
class: 'btn btn-xs btn-default artifact-download' do
|
||||
= icon('download')
|
||||
= number_to_human_size(file.metadata[:zipped], precision: 2)
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
- page_title 'Artifacts', "#{@build.name} (##{@build.id})", 'Builds'
|
||||
= render 'projects/builds/header_title'
|
||||
|
||||
#tree-holder.tree-holder
|
||||
.gray-content-block.top-block.clearfix
|
||||
.pull-right
|
||||
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build),
|
||||
class: 'btn btn-default' do
|
||||
= icon('download')
|
||||
Download artifacts archive
|
||||
.top-block.gray-content-block.clearfix
|
||||
.pull-right
|
||||
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build),
|
||||
class: 'btn btn-default' do
|
||||
= icon('download')
|
||||
Download artifacts archive
|
||||
|
||||
%div.tree-content-holder
|
||||
.table-holder
|
||||
%table.table.tree-table.table-striped
|
||||
.tree-holder
|
||||
%div.tree-content-holder
|
||||
%table.table.tree-table
|
||||
%thead
|
||||
%tr
|
||||
%th Name
|
||||
%th Size
|
||||
%th Download
|
||||
%th Compressed to
|
||||
= render partial: 'tree_directory', collection: @entry.directories(parent: true), as: :directory
|
||||
= render partial: 'tree_file', collection: @entry.files, as: :file
|
||||
|
||||
- if @entry.empty?
|
||||
.center Empty
|
||||
|
||||
:javascript
|
||||
$('.tree-holder').on('click', 'tr[data-link] a', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
|
||||
$('.tree-holder').on('click', 'tr[data-link]', function(e) {
|
||||
window.location = this.dataset.link;
|
||||
});
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
- if can?(current_user, :manage_builds, @project)
|
||||
.pull-left.hidden-xs
|
||||
- if @all_builds.running_or_pending.any?
|
||||
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
|
||||
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
|
||||
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
|
||||
|
||||
= link_to ci_lint_path, class: 'btn btn-default' do
|
||||
= icon('wrench')
|
||||
%span CI Lint
|
||||
|
||||
%ul.nav-links
|
||||
%li{class: ('active' if @scope.nil?)}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ Rails.application.configure do
|
||||
# Print deprecation notices to the Rails logger
|
||||
config.active_support.deprecation = :log
|
||||
|
||||
# Raise an error on page load if there are pending migrations
|
||||
config.active_record.migration_error = :page_load
|
||||
|
||||
# Only use best-standards-support built into browsers
|
||||
config.action_dispatch.best_standards_support = :builtin
|
||||
|
||||
|
||||
@@ -9,13 +9,8 @@ class Settings < Settingslogic
|
||||
gitlab.port.to_i == (gitlab.https ? 443 : 80)
|
||||
end
|
||||
|
||||
# get host without www, thanks to http://stackoverflow.com/a/6674363/1233435
|
||||
def get_host_without_www(url)
|
||||
url = CGI.escape(url)
|
||||
uri = URI.parse(url)
|
||||
uri = URI.parse("http://#{url}") if uri.scheme.nil?
|
||||
host = uri.host.downcase
|
||||
host.start_with?('www.') ? host[4..-1] : host
|
||||
def host_without_www(url)
|
||||
host(url).sub('www.', '')
|
||||
end
|
||||
|
||||
def build_gitlab_ci_url
|
||||
@@ -87,6 +82,17 @@ class Settings < Settingslogic
|
||||
custom_port
|
||||
]
|
||||
end
|
||||
|
||||
# Extract the host part of the given +url+.
|
||||
def host(url)
|
||||
url = url.downcase
|
||||
url = "http://#{url}" unless url.start_with?('http')
|
||||
|
||||
# Get rid of the path so that we don't even have to encode it
|
||||
url_without_path = url.sub(%r{(https?://[^\/]+)/?.*}, '\1')
|
||||
|
||||
URI.parse(url_without_path).host
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -228,7 +234,7 @@ Settings['gravatar'] ||= Settingslogic.new({})
|
||||
Settings.gravatar['enabled'] = true if Settings.gravatar['enabled'].nil?
|
||||
Settings.gravatar['plain_url'] ||= 'http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon'
|
||||
Settings.gravatar['ssl_url'] ||= 'https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon'
|
||||
Settings.gravatar['host'] = Settings.get_host_without_www(Settings.gravatar['plain_url'])
|
||||
Settings.gravatar['host'] = Settings.host_without_www(Settings.gravatar['plain_url'])
|
||||
|
||||
#
|
||||
# Cron Jobs
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
class AddServicesCategory < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :services, :category, :string, default: 'common', null: false
|
||||
|
||||
category = quote_column_name('category')
|
||||
type = quote_column_name('type')
|
||||
|
||||
execute <<-EOF
|
||||
UPDATE services
|
||||
SET #{category} = 'issue_tracker'
|
||||
WHERE #{type} IN (
|
||||
'CustomIssueTrackerService',
|
||||
'GitlabIssueTrackerService',
|
||||
'IssueTrackerService',
|
||||
'JiraService',
|
||||
'RedmineService'
|
||||
);
|
||||
EOF
|
||||
|
||||
execute <<-EOF
|
||||
UPDATE services
|
||||
SET #{category} = 'ci'
|
||||
WHERE #{type} IN (
|
||||
'BambooService',
|
||||
'BuildkiteService',
|
||||
'CiService',
|
||||
'DroneCiService',
|
||||
'GitlabCiService',
|
||||
'TeamcityService'
|
||||
);
|
||||
EOF
|
||||
|
||||
add_index :services, :category
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :services, :category
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
class AddServicesDefault < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :services, :default, :boolean, default: false
|
||||
|
||||
default = quote_column_name('default')
|
||||
type = quote_column_name('type')
|
||||
|
||||
execute <<-EOF
|
||||
UPDATE services
|
||||
SET #{default} = true
|
||||
WHERE #{type} = 'GitlabIssueTrackerService'
|
||||
EOF
|
||||
|
||||
add_index :services, :default
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :services, :default
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
@@ -6,5 +6,6 @@ class LimitsToMysql < ActiveRecord::Migration
|
||||
change_column :merge_request_diffs, :st_diffs, :text, limit: 2147483647
|
||||
change_column :snippets, :content, :text, limit: 2147483647
|
||||
change_column :notes, :st_diff, :text, limit: 2147483647
|
||||
change_column :events, :data, :text, limit: 2147483647
|
||||
end
|
||||
end
|
||||
|
||||
+16
-11
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160118155830) do
|
||||
ActiveRecord::Schema.define(version: 20160119145451) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -727,20 +727,24 @@ ActiveRecord::Schema.define(version: 20160118155830) do
|
||||
t.string "type"
|
||||
t.string "title"
|
||||
t.integer "project_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "active", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "active", null: false
|
||||
t.text "properties"
|
||||
t.boolean "template", default: false
|
||||
t.boolean "push_events", default: true
|
||||
t.boolean "issues_events", default: true
|
||||
t.boolean "merge_requests_events", default: true
|
||||
t.boolean "tag_push_events", default: true
|
||||
t.boolean "note_events", default: true, null: false
|
||||
t.boolean "build_events", default: false, null: false
|
||||
t.boolean "template", default: false
|
||||
t.boolean "push_events", default: true
|
||||
t.boolean "issues_events", default: true
|
||||
t.boolean "merge_requests_events", default: true
|
||||
t.boolean "tag_push_events", default: true
|
||||
t.boolean "note_events", default: true, null: false
|
||||
t.boolean "build_events", default: false, null: false
|
||||
t.string "category", default: "common", null: false
|
||||
t.boolean "default", default: false
|
||||
end
|
||||
|
||||
add_index "services", ["category"], name: "index_services_on_category", using: :btree
|
||||
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
|
||||
add_index "services", ["default"], name: "index_services_on_default", using: :btree
|
||||
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
|
||||
add_index "services", ["template"], name: "index_services_on_template", using: :btree
|
||||
|
||||
@@ -852,6 +856,7 @@ ActiveRecord::Schema.define(version: 20160118155830) 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,7 +8,7 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
|
||||
|
||||
# Install the database packages
|
||||
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
|
||||
|
||||
|
||||
# Ensure you have MySQL version 5.5.14 or later
|
||||
mysql --version
|
||||
|
||||
@@ -31,7 +31,7 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
|
||||
# Ensure you can use the InnoDB engine which is necessary to support long indexes
|
||||
# If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off"
|
||||
mysql> SET storage_engine=INNODB;
|
||||
|
||||
|
||||
# Create the GitLab production database
|
||||
mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
|
||||
|
||||
@@ -52,3 +52,25 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
|
||||
mysql> \q
|
||||
|
||||
# You are done installing the database and can go back to the rest of the installation.
|
||||
|
||||
## MySQL strings limits
|
||||
|
||||
After installation or upgrade, remember to run the `add_limits_mysql` Rake task:
|
||||
|
||||
```
|
||||
bundle exec rake add_limits_mysql
|
||||
```
|
||||
|
||||
The `text` type in MySQL has a different size limit than the `text` type in
|
||||
PostgreSQL. In MySQL `text` columns are limited to ~65kB, whereas in PostgreSQL
|
||||
`text` columns are limited up to ~1GB!
|
||||
|
||||
The `add_limits_mysql` Rake task converts some important `text` columns in the
|
||||
GitLab database to `longtext` columns, which can persist values of up to 4GB
|
||||
(sometimes less if the value contains multibyte characters).
|
||||
|
||||
Details can be found in the [PostgreSQL][postgres-text-type] and
|
||||
[MySQL][mysql-text-types] manuals.
|
||||
|
||||
[postgres-text-type]: http://www.postgresql.org/docs/9.1/static/datatype-character.html
|
||||
[mysql-text-types]: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html
|
||||
|
||||
@@ -48,7 +48,7 @@ which should already be on your system from GitLab 8.1.
|
||||
```bash
|
||||
cd /home/git/gitlab-workhorse
|
||||
sudo -u git -H git fetch --all
|
||||
sudo -u git -H git checkout 0.5.4
|
||||
sudo -u git -H git checkout 0.6.0
|
||||
sudo -u git -H make
|
||||
```
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ Depending on the installation method and your GitLab version, there are multiple
|
||||
## Miscellaneous
|
||||
|
||||
- [MySQL to PostgreSQL](mysql_to_postgresql.md) guides you through migrating your database from MySQL to PostgreSQL.
|
||||
- [MySQL installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/database_mysql.md) contains additional information about configuring GitLab to work with a MySQL database.
|
||||
|
||||
@@ -7,21 +7,21 @@ Feature: Project Builds Artifacts
|
||||
|
||||
Scenario: I download build artifacts
|
||||
Given recent build has artifacts available
|
||||
When I visit recent build summary page
|
||||
When I visit recent build details page
|
||||
And I click artifacts download button
|
||||
Then download of build artifacts archive starts
|
||||
|
||||
Scenario: I browse build artifacts
|
||||
Given recent build has artifacts available
|
||||
And recent build has artifacts metadata available
|
||||
When I visit recent build summary page
|
||||
When I visit recent build details page
|
||||
And I click artifacts browse button
|
||||
Then I should see content of artifacts archive
|
||||
|
||||
Scenario: I browse subdirectory of build artifacts
|
||||
Given recent build has artifacts available
|
||||
And recent build has artifacts metadata available
|
||||
When I visit recent build summary page
|
||||
When I visit recent build details page
|
||||
And I click artifacts browse button
|
||||
And I click link to subdirectory within build artifacts
|
||||
Then I should see content of subdirectory within artifacts archive
|
||||
@@ -30,7 +30,7 @@ Feature: Project Builds Artifacts
|
||||
Given recent build has artifacts available
|
||||
And recent build has artifacts metadata available
|
||||
And recent build artifacts contain directory with UTF-8 characters
|
||||
When I visit recent build summary page
|
||||
When I visit recent build details page
|
||||
And I click artifacts browse button
|
||||
And I navigate to directory with UTF-8 characters in name
|
||||
Then I should see content of directory with UTF-8 characters in name
|
||||
@@ -39,7 +39,7 @@ Feature: Project Builds Artifacts
|
||||
Given recent build has artifacts available
|
||||
And recent build has artifacts metadata available
|
||||
And recent build artifacts contain directory with invalid UTF-8 characters
|
||||
When I visit recent build summary page
|
||||
When I visit recent build details page
|
||||
And I click artifacts browse button
|
||||
And I navigate to parent directory of directory with invalid name
|
||||
Then I should not see directory with invalid name on the list
|
||||
@@ -47,7 +47,7 @@ Feature: Project Builds Artifacts
|
||||
Scenario: I download a single file from build artifacts
|
||||
Given recent build has artifacts available
|
||||
And recent build has artifacts metadata available
|
||||
When I visit recent build summary page
|
||||
When I visit recent build details page
|
||||
And I click artifacts browse button
|
||||
And I click download button for a file within build artifacts
|
||||
And I click a link to file within build artifacts
|
||||
Then download of a file extracted from build artifacts should start
|
||||
|
||||
@@ -5,7 +5,11 @@ Feature: Project Builds Summary
|
||||
And project has CI enabled
|
||||
And project has a recent build
|
||||
|
||||
Scenario: I browse build summary page
|
||||
When I visit recent build summary page
|
||||
Then I see summary for build
|
||||
Scenario: I browse build details page
|
||||
When I visit recent build details page
|
||||
Then I see details of a build
|
||||
And I see build trace
|
||||
|
||||
Scenario: I browse project builds page
|
||||
When I visit project builds page
|
||||
Then I see button to CI Lint
|
||||
|
||||
@@ -63,8 +63,8 @@ class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps
|
||||
end
|
||||
end
|
||||
|
||||
step 'I click download button for a file within build artifacts' do
|
||||
page.within('.tree-table') { first('.artifact-download').click }
|
||||
step 'I click a link to file within build artifacts' do
|
||||
page.within('.tree-table') { find_link('ci_artifacts.txt').click }
|
||||
end
|
||||
|
||||
step 'download of a file extracted from build artifacts should start' do
|
||||
|
||||
@@ -4,11 +4,18 @@ class Spinach::Features::ProjectBuildsSummary < Spinach::FeatureSteps
|
||||
include SharedBuilds
|
||||
include RepoHelpers
|
||||
|
||||
step 'I see summary for build' do
|
||||
step 'I see details of a build' do
|
||||
expect(page).to have_content "Build ##{@build.id}"
|
||||
end
|
||||
|
||||
step 'I see build trace' do
|
||||
expect(page).to have_css '#build-trace'
|
||||
end
|
||||
|
||||
step 'I see button to CI Lint' do
|
||||
page.within('.controls') do
|
||||
ci_lint_tool_link = page.find_link('CI Lint')
|
||||
expect(ci_lint_tool_link[:href]).to eq ci_lint_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,10 +10,14 @@ module SharedBuilds
|
||||
@build = create :ci_build, commit: ci_commit
|
||||
end
|
||||
|
||||
step 'I visit recent build summary page' do
|
||||
step 'I visit recent build details page' do
|
||||
visit namespace_project_build_path(@project.namespace, @project, @build)
|
||||
end
|
||||
|
||||
step 'I visit project builds page' do
|
||||
visit namespace_project_builds_path(@project.namespace, @project)
|
||||
end
|
||||
|
||||
step 'recent build has artifacts available' do
|
||||
artifacts = Rails.root + 'spec/fixtures/ci_build_artifacts.zip'
|
||||
archive = fixture_file_upload(artifacts, 'application/zip')
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ module Gitlab
|
||||
end
|
||||
|
||||
use_db && ActiveRecord::Base.connection.active? &&
|
||||
!ActiveRecord::Migrator.needs_migration? &&
|
||||
ActiveRecord::Base.connection.table_exists?('application_settings')
|
||||
|
||||
rescue ActiveRecord::NoDatabaseError
|
||||
|
||||
@@ -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
|
||||
|
||||
+16
-13
@@ -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),
|
||||
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
require_relative '../../config/initializers/1_settings'
|
||||
|
||||
describe Settings, lib: true do
|
||||
|
||||
describe '#host_without_www' do
|
||||
context 'URL with protocol' do
|
||||
it 'returns the host' do
|
||||
expect(Settings.host_without_www('http://foo.com')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('http://www.foo.com')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('http://secure.foo.com')).to eq 'secure.foo.com'
|
||||
expect(Settings.host_without_www('http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
|
||||
|
||||
expect(Settings.host_without_www('https://foo.com')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('https://www.foo.com')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('https://secure.foo.com')).to eq 'secure.foo.com'
|
||||
expect(Settings.host_without_www('https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'secure.gravatar.com'
|
||||
end
|
||||
end
|
||||
|
||||
context 'URL without protocol' do
|
||||
it 'returns the host' do
|
||||
expect(Settings.host_without_www('foo.com')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('www.foo.com')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('secure.foo.com')).to eq 'secure.foo.com'
|
||||
expect(Settings.host_without_www('www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
|
||||
end
|
||||
|
||||
context 'URL with user/port' do
|
||||
it 'returns the host' do
|
||||
expect(Settings.host_without_www('bob:pass@foo.com:8080')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('bob:pass@www.foo.com:8080')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com'
|
||||
expect(Settings.host_without_www('bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
|
||||
|
||||
expect(Settings.host_without_www('http://bob:pass@foo.com:8080')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('http://bob:pass@www.foo.com:8080')).to eq 'foo.com'
|
||||
expect(Settings.host_without_www('http://bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com'
|
||||
expect(Settings.host_without_www('http://bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
|
||||
end
|
||||
end
|
||||
end
|
||||
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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -227,7 +227,7 @@ describe NotificationService, services: true do
|
||||
end
|
||||
|
||||
describe :reassigned_issue do
|
||||
it 'should email new assignee' do
|
||||
it 'emails new assignee' do
|
||||
notification.reassigned_issue(issue, @u_disabled)
|
||||
|
||||
should_email(issue.assignee)
|
||||
@@ -238,6 +238,62 @@ describe NotificationService, services: true do
|
||||
should_not_email(@u_participating)
|
||||
should_not_email(@u_disabled)
|
||||
end
|
||||
|
||||
it 'emails previous assignee even if he has the "on mention" notif level' do
|
||||
issue.update_attribute(:assignee, @u_mentioned)
|
||||
issue.update_attributes(assignee: @u_watcher)
|
||||
notification.reassigned_issue(issue, @u_disabled)
|
||||
|
||||
should_email(@u_mentioned)
|
||||
should_email(@u_watcher)
|
||||
should_email(@u_participant_mentioned)
|
||||
should_email(@subscriber)
|
||||
should_not_email(@unsubscriber)
|
||||
should_not_email(@u_participating)
|
||||
should_not_email(@u_disabled)
|
||||
end
|
||||
|
||||
it 'emails new assignee even if he has the "on mention" notif level' do
|
||||
issue.update_attributes(assignee: @u_mentioned)
|
||||
notification.reassigned_issue(issue, @u_disabled)
|
||||
|
||||
expect(issue.assignee).to be @u_mentioned
|
||||
should_email(issue.assignee)
|
||||
should_email(@u_watcher)
|
||||
should_email(@u_participant_mentioned)
|
||||
should_email(@subscriber)
|
||||
should_not_email(@unsubscriber)
|
||||
should_not_email(@u_participating)
|
||||
should_not_email(@u_disabled)
|
||||
end
|
||||
|
||||
it 'emails new assignee' do
|
||||
issue.update_attribute(:assignee, @u_mentioned)
|
||||
notification.reassigned_issue(issue, @u_disabled)
|
||||
|
||||
expect(issue.assignee).to be @u_mentioned
|
||||
should_email(issue.assignee)
|
||||
should_email(@u_watcher)
|
||||
should_email(@u_participant_mentioned)
|
||||
should_email(@subscriber)
|
||||
should_not_email(@unsubscriber)
|
||||
should_not_email(@u_participating)
|
||||
should_not_email(@u_disabled)
|
||||
end
|
||||
|
||||
it 'does not email new assignee if they are the current user' do
|
||||
issue.update_attribute(:assignee, @u_mentioned)
|
||||
notification.reassigned_issue(issue, @u_mentioned)
|
||||
|
||||
expect(issue.assignee).to be @u_mentioned
|
||||
should_email(@u_watcher)
|
||||
should_email(@u_participant_mentioned)
|
||||
should_email(@subscriber)
|
||||
should_not_email(issue.assignee)
|
||||
should_not_email(@unsubscriber)
|
||||
should_not_email(@u_participating)
|
||||
should_not_email(@u_disabled)
|
||||
end
|
||||
end
|
||||
|
||||
describe :close_issue do
|
||||
|
||||
@@ -32,6 +32,7 @@ describe Projects::CreateService, services: true do
|
||||
|
||||
it { expect(@project).to be_valid }
|
||||
it { expect(@project.owner).to eq(@user) }
|
||||
it { expect(@project.team.masters).to include(@user) }
|
||||
it { expect(@project.namespace).to eq(@user.namespace) }
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user