Commit 0845f00a authored by Rémy Coutable's avatar Rémy Coutable

Merge remote-tracking branch 'origin/master' into ce-to-ee-2017-05-10

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parents 726914c2 df2d3773
...@@ -496,7 +496,13 @@ Style/TrailingBlankLines: ...@@ -496,7 +496,13 @@ Style/TrailingBlankLines:
# This cop checks for trailing comma in array and hash literals. # This cop checks for trailing comma in array and hash literals.
Style/TrailingCommaInLiteral: Style/TrailingCommaInLiteral:
Enabled: false Enabled: true
EnforcedStyleForMultiline: no_comma
# This cop checks for trailing comma in argument lists.
Style/TrailingCommaInArguments:
Enabled: true
EnforcedStyleForMultiline: no_comma
# Checks for %W when interpolation is not needed. # Checks for %W when interpolation is not needed.
Style/UnneededCapitalW: Style/UnneededCapitalW:
......
...@@ -369,13 +369,6 @@ Style/SymbolProc: ...@@ -369,13 +369,6 @@ Style/SymbolProc:
Style/TernaryParentheses: Style/TernaryParentheses:
Enabled: false Enabled: false
# Offense count: 53
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Enabled: false
# Offense count: 18 # Offense count: 18
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables. # Configuration parameters: AllowNamedUnderscoreVariables.
......
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 9.1.3 (2017-05-05)
- No changes.
- No changes.
- No changes.
- Respect project features when searching alternative branches with elasticsearch enabled.
- Fix for XSS in project mirror errors caused by Hamlit filter usage.
## 9.1.2 (2017-05-01) ## 9.1.2 (2017-05-01)
- No changes. - No changes.
...@@ -54,6 +62,11 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -54,6 +62,11 @@ Please view this file on the master branch, on stable branches it's out of date.
- Show user cohorts data when usage ping is enabled. - Show user cohorts data when usage ping is enabled.
- Visualise Canary Deployments. - Visualise Canary Deployments.
## 9.0.7 (2017-05-05)
- Respect project features when searching alternative branches with elasticsearch enabled.
- Fix for XSS in project mirror errors caused by Hamlit filter usage.
## 9.0.6 (2017-04-21) ## 9.0.6 (2017-04-21)
- Cache Gitlab::Geo queries. !1507 - Cache Gitlab::Geo queries. !1507
...@@ -129,6 +142,10 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -129,6 +142,10 @@ Please view this file on the master branch, on stable branches it's out of date.
- [Elasticsearch] More efficient search. - [Elasticsearch] More efficient search.
- Get Geo secondaries nodes statuses over AJAX. - Get Geo secondaries nodes statuses over AJAX.
## 8.17.6 (2017-05-05)
- Respect project features when searching alternative branches with elasticsearch enabled.
## 8.17.5 (2017-04-05) ## 8.17.5 (2017-04-05)
- No changes. - No changes.
......
...@@ -623,7 +623,7 @@ GitLabDropdown = (function() { ...@@ -623,7 +623,7 @@ GitLabDropdown = (function() {
var link = document.createElement('a'); var link = document.createElement('a');
link.href = url; link.href = url;
link.innerHTML = text; link.textContent = text;
if (selected) { if (selected) {
link.className = 'is-active'; link.className = 'is-active';
......
...@@ -24,7 +24,7 @@ const normalizeNewlines = function(str) { ...@@ -24,7 +24,7 @@ const normalizeNewlines = function(str) {
(function() { (function() {
this.Notes = (function() { this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3; const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const REGEX_SLASH_COMMANDS = /\/\w+/g; const REGEX_SLASH_COMMANDS = /^\/\w+/gm;
Notes.interval = null; Notes.interval = null;
......
...@@ -388,9 +388,9 @@ ...@@ -388,9 +388,9 @@
content: ''; content: '';
position: absolute; position: absolute;
top: 48%; top: 48%;
left: -48px; left: -44px;
border-top: 2px solid $border-color; border-top: 2px solid $border-color;
width: 48px; width: 44px;
height: 1px; height: 1px;
} }
} }
...@@ -490,7 +490,11 @@ ...@@ -490,7 +490,11 @@
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
// Action Icons in big pipeline-graph nodes // Action Icons in big pipeline-graph nodes
<<<<<<< HEAD
> div > .ci-action-icon-container .ci-action-icon-wrapper { > div > .ci-action-icon-container .ci-action-icon-wrapper {
=======
.ci-action-icon-container .ci-action-icon-wrapper {
>>>>>>> origin/master
height: 30px; height: 30px;
width: 30px; width: 30px;
background: $white-light; background: $white-light;
...@@ -515,7 +519,11 @@ ...@@ -515,7 +519,11 @@
} }
} }
<<<<<<< HEAD
> div > .ci-action-icon-container { > div > .ci-action-icon-container {
=======
.ci-action-icon-container {
>>>>>>> origin/master
position: absolute; position: absolute;
right: 5px; right: 5px;
top: 5px; top: 5px;
...@@ -545,7 +553,11 @@ ...@@ -545,7 +553,11 @@
} }
} }
<<<<<<< HEAD
> div > .build-content { > div > .build-content {
=======
.build-content {
>>>>>>> origin/master
display: inline-block; display: inline-block;
padding: 8px 10px 9px; padding: 8px 10px 9px;
width: 100%; width: 100%;
......
...@@ -174,7 +174,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -174,7 +174,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:shared_runners_minutes, :shared_runners_minutes,
:minimum_mirror_sync_time, :minimum_mirror_sync_time,
:geo_status_timeout, :geo_status_timeout,
:elasticsearch_experimental_indexer, :elasticsearch_experimental_indexer
] ]
end end
end end
...@@ -60,6 +60,7 @@ class Admin::HooksController < Admin::ApplicationController ...@@ -60,6 +60,7 @@ class Admin::HooksController < Admin::ApplicationController
:enable_ssl_verification, :enable_ssl_verification,
:push_events, :push_events,
:tag_push_events, :tag_push_events,
:repository_update_events,
:token, :token,
:url :url
) )
......
...@@ -45,7 +45,7 @@ class AutocompleteController < ApplicationController ...@@ -45,7 +45,7 @@ class AutocompleteController < ApplicationController
no_project = { no_project = {
id: 0, id: 0,
name_with_namespace: 'No project', name_with_namespace: 'No project'
} }
projects.unshift(no_project) unless params[:offset_id].present? projects.unshift(no_project) unless params[:offset_id].present?
......
...@@ -23,7 +23,7 @@ module LfsRequest ...@@ -23,7 +23,7 @@ module LfsRequest
render( render(
json: { json: {
message: 'Git LFS is not enabled on this GitLab server, contact your admin.', message: 'Git LFS is not enabled on this GitLab server, contact your admin.',
documentation_url: help_url, documentation_url: help_url
}, },
status: 501 status: 501
) )
...@@ -48,7 +48,7 @@ module LfsRequest ...@@ -48,7 +48,7 @@ module LfsRequest
render( render(
json: { json: {
message: 'Access forbidden. Check your access level.', message: 'Access forbidden. Check your access level.',
documentation_url: help_url, documentation_url: help_url
}, },
content_type: "application/vnd.git-lfs+json", content_type: "application/vnd.git-lfs+json",
status: 403 status: 403
...@@ -59,7 +59,7 @@ module LfsRequest ...@@ -59,7 +59,7 @@ module LfsRequest
render( render(
json: { json: {
message: 'Not found.', message: 'Not found.',
documentation_url: help_url, documentation_url: help_url
}, },
content_type: "application/vnd.git-lfs+json", content_type: "application/vnd.git-lfs+json",
status: 404 status: 404
...@@ -123,7 +123,7 @@ module LfsRequest ...@@ -123,7 +123,7 @@ module LfsRequest
render( render(
json: { json: {
message: Gitlab::RepositorySizeError.new(project).push_error(@exceeded_limit), message: Gitlab::RepositorySizeError.new(project).push_error(@exceeded_limit),
documentation_url: help_url, documentation_url: help_url
}, },
content_type: "application/vnd.git-lfs+json", content_type: "application/vnd.git-lfs+json",
status: 406 status: 406
......
class Dashboard::SnippetsController < Dashboard::ApplicationController class Dashboard::SnippetsController < Dashboard::ApplicationController
def index def index
@snippets = SnippetsFinder.new.execute( @snippets = SnippetsFinder.new(
current_user, current_user,
filter: :by_user, author: current_user,
user: current_user,
scope: params[:scope] scope: params[:scope]
) ).execute
@snippets = @snippets.page(params[:page]) @snippets = @snippets.page(params[:page])
end end
end end
class Explore::GroupsController < Explore::ApplicationController class Explore::GroupsController < Explore::ApplicationController
def index def index
@groups = GroupsFinder.new.execute(current_user) @groups = GroupsFinder.new(current_user).execute
@groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present? @groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present?
@groups = @groups.sort(@sort = params[:sort]) @groups = @groups.sort(@sort = params[:sort])
@groups = @groups.page(params[:page]) @groups = @groups.page(params[:page])
......
class Explore::SnippetsController < Explore::ApplicationController class Explore::SnippetsController < Explore::ApplicationController
def index def index
@snippets = SnippetsFinder.new.execute(current_user, filter: :all) @snippets = SnippetsFinder.new(current_user).execute
@snippets = @snippets.page(params[:page]) @snippets = @snippets.page(params[:page])
end end
end end
...@@ -64,7 +64,7 @@ class GroupsController < Groups::ApplicationController ...@@ -64,7 +64,7 @@ class GroupsController < Groups::ApplicationController
end end
def subgroups def subgroups
@nested_groups = group.children @nested_groups = GroupsFinder.new(current_user, parent: group).execute
@nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present? @nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present?
end end
......
...@@ -5,7 +5,7 @@ class HealthController < ActionController::Base ...@@ -5,7 +5,7 @@ class HealthController < ActionController::Base
CHECKS = [ CHECKS = [
Gitlab::HealthChecks::DbCheck, Gitlab::HealthChecks::DbCheck,
Gitlab::HealthChecks::RedisCheck, Gitlab::HealthChecks::RedisCheck,
Gitlab::HealthChecks::FsShardsCheck, Gitlab::HealthChecks::FsShardsCheck
].freeze ].freeze
def readiness def readiness
......
...@@ -4,7 +4,7 @@ class JwtController < ApplicationController ...@@ -4,7 +4,7 @@ class JwtController < ApplicationController
before_action :authenticate_project_or_user before_action :authenticate_project_or_user
SERVICES = { SERVICES = {
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService, Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService
}.freeze }.freeze
def auth def auth
......
...@@ -33,7 +33,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController ...@@ -33,7 +33,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:color_scheme_id, :color_scheme_id,
:layout, :layout,
:dashboard, :dashboard,
:project_view, :project_view
) )
end end
end end
...@@ -6,7 +6,7 @@ class Projects::DeploymentsController < Projects::ApplicationController ...@@ -6,7 +6,7 @@ class Projects::DeploymentsController < Projects::ApplicationController
deployments = environment.deployments.reorder(created_at: :desc) deployments = environment.deployments.reorder(created_at: :desc)
deployments = deployments.where('created_at > ?', params[:after].to_time) if params[:after]&.to_time deployments = deployments.where('created_at > ?', params[:after].to_time) if params[:after]&.to_time
render json: { deployments: DeploymentSerializer.new(user: @current_user, project: project) render json: { deployments: DeploymentSerializer.new(project: project)
.represent_concise(deployments) } .represent_concise(deployments) }
end end
......
...@@ -143,7 +143,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -143,7 +143,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
if rollout_status.nil? if rollout_status.nil?
render body: nil, status: 204 # no result yet render body: nil, status: 204 # no result yet
else else
serializer = RolloutStatusSerializer.new(project: @project, user: @current_user) serializer = RolloutStatusSerializer.new(project: @project, current_user: @current_user)
render json: serializer.represent(rollout_status) render json: serializer.represent(rollout_status)
end end
end end
......
...@@ -217,7 +217,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -217,7 +217,7 @@ class Projects::IssuesController < Projects::ApplicationController
description_text: @issue.description, description_text: @issue.description,
task_status: @issue.task_status, task_status: @issue.task_status,
issue_number: @issue.iid, issue_number: @issue.iid,
updated_at: @issue.updated_at, updated_at: @issue.updated_at
} }
end end
...@@ -277,7 +277,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -277,7 +277,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue_params def issue_params
params.require(:issue).permit( params.require(:issue).permit(
:title, :position, :description, :confidential, :weight, :title, :position, :description, :confidential, :weight,
:milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [], assignee_ids: [], :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [], assignee_ids: []
) )
end end
......
...@@ -22,7 +22,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController ...@@ -22,7 +22,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
render( render(
json: { json: {
message: 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.', message: 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.',
documentation_url: "#{Gitlab.config.gitlab.url}/help", documentation_url: "#{Gitlab.config.gitlab.url}/help"
}, },
status: 501 status: 501
) )
...@@ -55,7 +55,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController ...@@ -55,7 +55,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
else else
object[:error] = { object[:error] = {
code: 404, code: 404,
message: "Object does not exist on the server or you don't have permissions to access it", message: "Object does not exist on the server or you don't have permissions to access it"
} }
end end
end end
......
...@@ -44,7 +44,7 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -44,7 +44,7 @@ class Projects::PipelinesController < Projects::ApplicationController
all: @pipelines_count, all: @pipelines_count,
running: @running_count, running: @running_count,
pending: @pending_count, pending: @pending_count,
finished: @finished_count, finished: @finished_count
} }
} }
end end
......
...@@ -23,12 +23,11 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -23,12 +23,11 @@ class Projects::SnippetsController < Projects::ApplicationController
respond_to :html respond_to :html
def index def index
@snippets = SnippetsFinder.new.execute( @snippets = SnippetsFinder.new(
current_user, current_user,
filter: :by_project,
project: @project, project: @project,
scope: params[:scope] scope: params[:scope]
) ).execute
@snippets = @snippets.page(params[:page]) @snippets = @snippets.page(params[:page])
if @snippets.out_of_range? && @snippets.total_pages != 0 if @snippets.out_of_range? && @snippets.total_pages != 0
redirect_to namespace_project_snippets_path(page: @snippets.total_pages) redirect_to namespace_project_snippets_path(page: @snippets.total_pages)
......
...@@ -48,7 +48,7 @@ class Projects::TreeController < Projects::ApplicationController ...@@ -48,7 +48,7 @@ class Projects::TreeController < Projects::ApplicationController
@dir_name = File.join(@path, params[:dir_name]) @dir_name = File.join(@path, params[:dir_name])
@commit_params = { @commit_params = {
file_path: @dir_name, file_path: @dir_name,
commit_message: params[:commit_message], commit_message: params[:commit_message]
} }
end end
end end
...@@ -221,7 +221,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -221,7 +221,7 @@ class ProjectsController < Projects::ApplicationController
branches = BranchesFinder.new(@repository, params).execute.map(&:name) branches = BranchesFinder.new(@repository, params).execute.map(&:name)
options = { options = {
'Branches' => branches.take(100), 'Branches' => branches.take(100)
} }
unless @repository.tag_count.zero? unless @repository.tag_count.zero?
......
...@@ -27,12 +27,8 @@ class SnippetsController < ApplicationController ...@@ -27,12 +27,8 @@ class SnippetsController < ApplicationController
return render_404 unless @user return render_404 unless @user
@snippets = SnippetsFinder.new.execute(current_user, { @snippets = SnippetsFinder.new(current_user, author: @user, scope: params[:scope])
filter: :by_user, .execute.page(params[:page])
user: @user,
scope: params[:scope]
})
.page(params[:page])
render 'index' render 'index'
else else
...@@ -103,20 +99,20 @@ class SnippetsController < ApplicationController ...@@ -103,20 +99,20 @@ class SnippetsController < ApplicationController
protected protected
def snippet def snippet
@snippet ||= if current_user @snippet ||= PersonalSnippet.find_by(id: params[:id])
PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
current_user.id,
[Snippet::PUBLIC, Snippet::INTERNAL]).
find(params[:id])
else
PersonalSnippet.find(params[:id])
end
end end
alias_method :awardable, :snippet alias_method :awardable, :snippet
alias_method :spammable, :snippet alias_method :spammable, :snippet
def authorize_read_snippet! def authorize_read_snippet!
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet) return if can?(current_user, :read_personal_snippet, @snippet)
if current_user
render_404
else
authenticate_user!
end
end end
def authorize_update_snippet! def authorize_update_snippet!
......
...@@ -128,12 +128,11 @@ class UsersController < ApplicationController ...@@ -128,12 +128,11 @@ class UsersController < ApplicationController
end end
def load_snippets def load_snippets
@snippets = SnippetsFinder.new.execute( @snippets = SnippetsFinder.new(
current_user, current_user,
filter: :by_user, author: user,
user: user,
scope: params[:scope] scope: params[:scope]
).page(params[:page]) ).execute.page(params[:page])
end end
def projects_for_current_user def projects_for_current_user
......
class GroupsFinder < UnionFinder class GroupsFinder < UnionFinder
def execute(current_user = nil) def initialize(current_user = nil, params = {})
segments = all_groups(current_user) @current_user = current_user
@params = params
end
find_union(segments, Group).with_route.order_id_desc def execute
groups = find_union(all_groups, Group).with_route.order_id_desc
by_parent(groups)
end end
private private
def all_groups(current_user) attr_reader :current_user, :params
def all_groups
groups = [] groups = []
groups << current_user.authorized_groups if current_user groups << current_user.authorized_groups if current_user
...@@ -15,4 +21,10 @@ class GroupsFinder < UnionFinder ...@@ -15,4 +21,10 @@ class GroupsFinder < UnionFinder
groups groups
end end
def by_parent(groups)
return groups unless params[:parent]
groups.where(parent: params[:parent])
end
end end
...@@ -67,7 +67,7 @@ class NotesFinder ...@@ -67,7 +67,7 @@ class NotesFinder
when "merge_request" when "merge_request"
MergeRequestsFinder.new(@current_user, project_id: @project.id).execute MergeRequestsFinder.new(@current_user, project_id: @project.id).execute
when "snippet", "project_snippet" when "snippet", "project_snippet"
SnippetsFinder.new.execute(@current_user, filter: :by_project, project: @project) SnippetsFinder.new(@current_user, project: @project).execute
when "personal_snippet" when "personal_snippet"
PersonalSnippet.all PersonalSnippet.all
else else
......
class SnippetsFinder class SnippetsFinder < UnionFinder
def execute(current_user, params = {}) attr_accessor :current_user, :params
filter = params[:filter]
user = params.fetch(:user, current_user) def initialize(current_user, params = {})
@current_user = current_user
case filter @params = params
when :all then end
snippets(current_user).fresh
when :public then def execute
Snippet.are_public.fresh items = init_collection
when :by_user then items = by_project(items)
by_user(current_user, user, params[:scope]) items = by_author(items)
when :by_project items = by_visibility(items)
by_project(current_user, params[:project], params[:scope])
end items.fresh
end end
private private
def snippets(current_user) def init_collection
if current_user items = Snippet.all
Snippet.public_and_internal
else accessible(items)
# Not authenticated
#
# Return only:
# public snippets
Snippet.are_public
end
end end
def by_user(current_user, user, scope) def accessible(items)
snippets = user.snippets.fresh segments = []
segments << items.public_to_user(current_user)
segments << authorized_to_user(items) if current_user
if current_user find_union(segments, Snippet)
include_private = user == current_user
by_scope(snippets, scope, include_private)
else
snippets.are_public
end
end end
def by_project(current_user, project, scope) def authorized_to_user(items)
snippets = project.snippets.fresh items.where(
'author_id = :author_id
OR project_id IN (:project_ids)',
author_id: current_user.id,
project_ids: current_user.authorized_projects.select(:id))
end
if current_user def by_visibility(items)
include_private = project.team.member?(current_user) || current_user.admin_or_auditor? visibility = params[:visibility] || visibility_from_scope
by_scope(snippets, scope, include_private)
else return items unless visibility
snippets.are_public
end items.where(visibility_level: visibility)
end
def by_author(items)
return items unless params[:author]
items.where(author_id: params[:author].id)
end
def by_project(items)
return items unless params[:project]
items.where(project_id: params[:project].id)
end end
def by_scope(snippets, scope = nil, include_private = false) def visibility_from_scope
case scope.to_s case params[:scope].to_s
when 'are_private' when 'are_private'
include_private ? snippets.are_private : Snippet.none Snippet::PRIVATE
when 'are_internal' when 'are_internal'
snippets.are_internal Snippet::INTERNAL
when 'are_public' when 'are_public'
snippets.are_public Snippet::PUBLIC
else else
include_private ? snippets : snippets.public_and_internal nil
end end
end end
end end
...@@ -98,7 +98,7 @@ module DiffHelper ...@@ -98,7 +98,7 @@ module DiffHelper
[ [
content_tag(:span, link_to(truncate(blob.name, length: 40), tree)), content_tag(:span, link_to(truncate(blob.name, length: 40), tree)),
'@', '@',
content_tag(:span, commit_id, class: 'monospace'), content_tag(:span, commit_id, class: 'monospace')
].join(' ').html_safe ].join(' ').html_safe
end end
......
...@@ -12,7 +12,7 @@ module EmailsHelper ...@@ -12,7 +12,7 @@ module EmailsHelper
"action" => { "action" => {
"@type" => "ViewAction", "@type" => "ViewAction",
"name" => name, "name" => name,
"url" => url, "url" => url
} }
} }
......
...@@ -41,7 +41,7 @@ module EventsHelper ...@@ -41,7 +41,7 @@ module EventsHelper
link_opts = { link_opts = {
class: "event-filter-link", class: "event-filter-link",
id: "#{key}_event_filter", id: "#{key}_event_filter",
title: "Filter by #{tooltip.downcase}", title: "Filter by #{tooltip.downcase}"
} }
content_tag :li, class: active do content_tag :li, class: active do
......
...@@ -10,7 +10,7 @@ module ExploreHelper ...@@ -10,7 +10,7 @@ module ExploreHelper
personal: params[:personal], personal: params[:personal],
archived: params[:archived], archived: params[:archived],
shared: params[:shared], shared: params[:shared],
namespace_id: params[:namespace_id], namespace_id: params[:namespace_id]
} }
options = exist_opts.merge(options).delete_if { |key, value| value.blank? } options = exist_opts.merge(options).delete_if { |key, value| value.blank? }
......
...@@ -32,7 +32,7 @@ module MarkupHelper ...@@ -32,7 +32,7 @@ module MarkupHelper
context = { context = {
project: @project, project: @project,
current_user: (current_user if defined?(current_user)), current_user: (current_user if defined?(current_user)),
pipeline: :single_line, pipeline: :single_line
} }
gfm_body = Banzai.render(body, context) gfm_body = Banzai.render(body, context)
...@@ -116,13 +116,13 @@ module MarkupHelper ...@@ -116,13 +116,13 @@ module MarkupHelper
if gitlab_markdown?(file_name) if gitlab_markdown?(file_name)
markdown_unsafe(text, context) markdown_unsafe(text, context)
elsif asciidoc?(file_name) elsif asciidoc?(file_name)
asciidoc_unsafe(text) asciidoc_unsafe(text, context)
elsif plain?(file_name) elsif plain?(file_name)
content_tag :pre, class: 'plain-readme' do content_tag :pre, class: 'plain-readme' do
text text
end end
else else
other_markup_unsafe(file_name, text) other_markup_unsafe(file_name, text, context)
end end
rescue RuntimeError rescue RuntimeError
simple_format(text) simple_format(text)
...@@ -217,12 +217,12 @@ module MarkupHelper ...@@ -217,12 +217,12 @@ module MarkupHelper
Banzai.render(text, context) Banzai.render(text, context)
end end
def asciidoc_unsafe(text) def asciidoc_unsafe(text, context = {})
Gitlab::Asciidoc.render(text) Gitlab::Asciidoc.render(text, context)
end end
def other_markup_unsafe(file_name, text) def other_markup_unsafe(file_name, text, context = {})
Gitlab::OtherMarkup.render(file_name, text) Gitlab::OtherMarkup.render(file_name, text, context)
end end
def prepare_for_rendering(html, context = {}) def prepare_for_rendering(html, context = {})
......
...@@ -54,7 +54,7 @@ module MergeRequestsHelper ...@@ -54,7 +54,7 @@ module MergeRequestsHelper
source_project_id: merge_request.source_project_id, source_project_id: merge_request.source_project_id,
target_project_id: merge_request.target_project_id, target_project_id: merge_request.target_project_id,
source_branch: merge_request.source_branch, source_branch: merge_request.source_branch,
target_branch: merge_request.target_branch, target_branch: merge_request.target_branch
}, },
change_branches: true change_branches: true
) )
......
...@@ -19,7 +19,7 @@ module NotesHelper ...@@ -19,7 +19,7 @@ module NotesHelper
id: noteable.id, id: noteable.id,
class: noteable.class.name, class: noteable.class.name,
resources: noteable.class.table_name, resources: noteable.class.table_name,
project_id: noteable.project.id, project_id: noteable.project.id
}.to_json }.to_json
end end
...@@ -34,7 +34,7 @@ module NotesHelper ...@@ -34,7 +34,7 @@ module NotesHelper
data = { data = {
line_code: line_code, line_code: line_code,
line_type: line_type, line_type: line_type
} }
if @use_legacy_diff_notes if @use_legacy_diff_notes
......
...@@ -50,7 +50,7 @@ module SearchHelper ...@@ -50,7 +50,7 @@ module SearchHelper
{ category: "Settings", label: "User settings", url: profile_path }, { category: "Settings", label: "User settings", url: profile_path },
{ category: "Settings", label: "SSH Keys", url: profile_keys_path }, { category: "Settings", label: "SSH Keys", url: profile_keys_path },
{ category: "Settings", label: "Dashboard", url: root_path }, { category: "Settings", label: "Dashboard", url: root_path },
{ category: "Settings", label: "Admin Section", url: admin_root_path }, { category: "Settings", label: "Admin Section", url: admin_root_path }
] ]
end end
...@@ -65,7 +65,7 @@ module SearchHelper ...@@ -65,7 +65,7 @@ module SearchHelper
{ category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") }, { category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") },
{ category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks/system_hooks") }, { category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks/system_hooks") },
{ category: "Help", label: "Webhooks Help", url: help_page_path("user/project/integrations/webhooks") }, { category: "Help", label: "Webhooks Help", url: help_page_path("user/project/integrations/webhooks") },
{ category: "Help", label: "Workflow Help", url: help_page_path("workflow/README") }, { category: "Help", label: "Workflow Help", url: help_page_path("workflow/README") }
] ]
end end
...@@ -84,7 +84,7 @@ module SearchHelper ...@@ -84,7 +84,7 @@ module SearchHelper
{ category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) }, { category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
{ category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) }, { category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
{ category: "Current Project", label: "Members", url: namespace_project_settings_members_path(@project.namespace, @project) }, { category: "Current Project", label: "Members", url: namespace_project_settings_members_path(@project.namespace, @project) },
{ category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) }, { category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) }
] ]
else else
[] []
......
...@@ -84,7 +84,7 @@ module SelectsHelper ...@@ -84,7 +84,7 @@ module SelectsHelper
current_user: opts[:current_user] || false, current_user: opts[:current_user] || false,
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches], "push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
author_id: opts[:author_id] || '', author_id: opts[:author_id] || '',
skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil, skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil
} }
end end
end end
...@@ -60,7 +60,7 @@ module SortingHelper ...@@ -60,7 +60,7 @@ module SortingHelper
sort_value_due_date_soon => sort_title_due_date_soon, sort_value_due_date_soon => sort_title_due_date_soon,
sort_value_due_date_later => sort_title_due_date_later, sort_value_due_date_later => sort_title_due_date_later,
sort_value_start_date_soon => sort_title_start_date_soon, sort_value_start_date_soon => sort_title_start_date_soon,
sort_value_start_date_later => sort_title_start_date_later, sort_value_start_date_later => sort_title_start_date_later
} }
end end
......
module SubmoduleHelper module SubmoduleHelper
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
VALID_SUBMODULE_PROTOCOLS = %w[http https git ssh].freeze
# links to files listing for submodule if submodule is a project on this server # links to files listing for submodule if submodule is a project on this server
def submodule_links(submodule_item, ref = nil, repository = @repository) def submodule_links(submodule_item, ref = nil, repository = @repository)
url = repository.submodule_url_for(ref, submodule_item.path) url = repository.submodule_url_for(ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/ if url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
namespace, project = $1, $2
namespace = $1 project.sub!(/\.git\z/, '')
project = $2
project.chomp!('.git')
if self_url?(url, namespace, project) if self_url?(url, namespace, project)
return namespace_project_path(namespace, project), [namespace_project_path(namespace, project),
namespace_project_tree_path(namespace, project, namespace_project_tree_path(namespace, project, submodule_item.id)]
submodule_item.id) elsif relative_self_url?(url)
elsif relative_self_url?(url) relative_self_links(url, submodule_item.id)
relative_self_links(url, submodule_item.id) elsif github_dot_com_url?(url)
elsif github_dot_com_url?(url) standard_links('github.com', namespace, project, submodule_item.id)
standard_links('github.com', namespace, project, submodule_item.id) elsif gitlab_dot_com_url?(url)
elsif gitlab_dot_com_url?(url) standard_links('gitlab.com', namespace, project, submodule_item.id)
standard_links('gitlab.com', namespace, project, submodule_item.id) else
[sanitize_submodule_url(url), nil]
end
else else
return url, nil [sanitize_submodule_url(url), nil]
end end
end end
...@@ -73,4 +75,16 @@ module SubmoduleHelper ...@@ -73,4 +75,16 @@ module SubmoduleHelper
namespace_project_tree_path(namespace, base, commit) namespace_project_tree_path(namespace, base, commit)
] ]
end end
def sanitize_submodule_url(url)
uri = URI.parse(url)
if uri.scheme.in?(VALID_SUBMODULE_PROTOCOLS)
uri.to_s
else
nil
end
rescue URI::InvalidURIError
nil
end
end end
...@@ -63,7 +63,7 @@ module TodosHelper ...@@ -63,7 +63,7 @@ module TodosHelper
project_id: params[:project_id], project_id: params[:project_id],
author_id: params[:author_id], author_id: params[:author_id],
type: params[:type], type: params[:type],
action_id: params[:action_id], action_id: params[:action_id]
} }
end end
......
...@@ -318,7 +318,7 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -318,7 +318,7 @@ class ApplicationSetting < ActiveRecord::Base
aws: elasticsearch_aws, aws: elasticsearch_aws,
aws_access_key: elasticsearch_aws_access_key, aws_access_key: elasticsearch_aws_access_key,
aws_secret_access_key: elasticsearch_aws_secret_access_key, aws_secret_access_key: elasticsearch_aws_secret_access_key,
aws_region: elasticsearch_aws_region, aws_region: elasticsearch_aws_region
} }
end end
......
...@@ -33,7 +33,7 @@ class Blob < SimpleDelegator ...@@ -33,7 +33,7 @@ class Blob < SimpleDelegator
BlobViewer::PDF, BlobViewer::PDF,
BlobViewer::BinarySTL, BlobViewer::BinarySTL,
BlobViewer::TextSTL, BlobViewer::TextSTL
].freeze ].freeze
BINARY_VIEWERS = RICH_VIEWERS.select(&:binary?).freeze BINARY_VIEWERS = RICH_VIEWERS.select(&:binary?).freeze
......
...@@ -49,7 +49,7 @@ class Commit ...@@ -49,7 +49,7 @@ class Commit
def max_diff_options def max_diff_options
{ {
max_files: DIFF_HARD_LIMIT_FILES, max_files: DIFF_HARD_LIMIT_FILES,
max_lines: DIFF_HARD_LIMIT_LINES, max_lines: DIFF_HARD_LIMIT_LINES
} }
end end
......
...@@ -39,7 +39,7 @@ class DiffDiscussion < Discussion ...@@ -39,7 +39,7 @@ class DiffDiscussion < Discussion
def reply_attributes def reply_attributes
super.merge( super.merge(
original_position: original_position.to_json, original_position: original_position.to_json,
position: position.to_json, position: position.to_json
) )
end end
end end
...@@ -62,7 +62,7 @@ class Environment < ActiveRecord::Base ...@@ -62,7 +62,7 @@ class Environment < ActiveRecord::Base
def predefined_variables def predefined_variables
[ [
{ key: 'CI_ENVIRONMENT_NAME', value: name, public: true }, { key: 'CI_ENVIRONMENT_NAME', value: name, public: true },
{ key: 'CI_ENVIRONMENT_SLUG', value: slug, public: true }, { key: 'CI_ENVIRONMENT_SLUG', value: slug, public: true }
] ]
end end
......
...@@ -159,8 +159,9 @@ class GeoNode < ActiveRecord::Base ...@@ -159,8 +159,9 @@ class GeoNode < ActiveRecord::Base
self.build_system_hook if system_hook.nil? self.build_system_hook if system_hook.nil?
self.system_hook.token = SecureRandom.hex(20) unless self.system_hook.token.present? self.system_hook.token = SecureRandom.hex(20) unless self.system_hook.token.present?
self.system_hook.url = geo_events_url if uri.present? self.system_hook.url = geo_events_url if uri.present?
self.system_hook.push_events = true self.system_hook.push_events = false
self.system_hook.tag_push_events = true self.system_hook.tag_push_events = false
self.system_hook.repository_update_events = true
end end
def expire_cache! def expire_cache!
......
class SystemHook < WebHook class SystemHook < WebHook
scope :repository_update_hooks, -> { where(repository_update_events: true) }
default_value_for :push_events, false
default_value_for :repository_update_events, true
def async_execute(data, hook_name) def async_execute(data, hook_name)
Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name) Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name)
end end
def self.repository_update_hooks
GeoNode.where(primary: false).map(&:system_hook)
end
end end
...@@ -10,6 +10,7 @@ class WebHook < ActiveRecord::Base ...@@ -10,6 +10,7 @@ class WebHook < ActiveRecord::Base
default_value_for :tag_push_events, false default_value_for :tag_push_events, false
default_value_for :build_events, false default_value_for :build_events, false
default_value_for :pipeline_events, false default_value_for :pipeline_events, false
default_value_for :repository_update_events, false
default_value_for :enable_ssl_verification, true default_value_for :enable_ssl_verification, true
scope :push_hooks, -> { where(push_events: true) } scope :push_hooks, -> { where(push_events: true) }
...@@ -31,7 +32,7 @@ class WebHook < ActiveRecord::Base ...@@ -31,7 +32,7 @@ class WebHook < ActiveRecord::Base
post_url = url.gsub("#{parsed_url.userinfo}@", '') post_url = url.gsub("#{parsed_url.userinfo}@", '')
auth = { auth = {
username: CGI.unescape(parsed_url.user), username: CGI.unescape(parsed_url.user),
password: CGI.unescape(parsed_url.password), password: CGI.unescape(parsed_url.password)
} }
response = WebHook.post(post_url, response = WebHook.post(post_url,
body: data.to_json, body: data.to_json,
......
...@@ -76,7 +76,7 @@ class Key < ActiveRecord::Base ...@@ -76,7 +76,7 @@ class Key < ActiveRecord::Base
GitlabShellWorker.perform_async( GitlabShellWorker.perform_async(
:remove_key, :remove_key,
shell_id, shell_id,
key, key
) )
end end
......
class License < ActiveRecord::Base class License < ActiveRecord::Base
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
EES_FEATURES = [
# ..
].freeze
EEP_FEATURES = [
*EES_FEATURES,
{ 'GitLab_DeployBoard' => 1 },
{ 'GitLab_FileLocks' => 1 },
{ 'GitLab_Geo' => 1 },
{ 'GitLab_Auditor_User' => 1 },
{ 'GitLab_ServiceDesk' => 1 }
].freeze
FEATURES_BY_PLAN = {
'starter' => EES_FEATURES,
'premium' => EEP_FEATURES
}.freeze
validate :valid_license validate :valid_license
validate :check_users_limit, if: :new_record?, unless: :validate_with_trueup? validate :check_users_limit, if: :new_record?, unless: :validate_with_trueup?
validate :check_trueup, unless: :persisted?, if: :validate_with_trueup? validate :check_trueup, unless: :persisted?, if: :validate_with_trueup?
...@@ -14,6 +32,10 @@ class License < ActiveRecord::Base ...@@ -14,6 +32,10 @@ class License < ActiveRecord::Base
scope :previous, -> { order(created_at: :desc).offset(1) } scope :previous, -> { order(created_at: :desc).offset(1) }
class << self class << self
def features_for_plan(plan)
FEATURES_BY_PLAN.fetch(plan, []).reduce({}, :merge)
end
def current def current
if RequestStore.active? if RequestStore.active?
RequestStore.fetch(:current_license) { load_license } RequestStore.fetch(:current_license) { load_license }
...@@ -83,8 +105,14 @@ class License < ActiveRecord::Base ...@@ -83,8 +105,14 @@ class License < ActiveRecord::Base
end end
end end
# New licenses persists only the `plan` (premium, starter, ..). But, old licenses
# keep `add_ons`, therefore this method needs to be backward-compatible in that sense.
# See https://gitlab.com/gitlab-org/gitlab-ee/issues/2019
def add_ons def add_ons
restricted_attr(:add_ons, {}) explicit_add_ons = restricted_attr(:add_ons, {})
plan_features = self.class.features_for_plan(plan)
explicit_add_ons.merge(plan_features)
end end
def add_on?(code) def add_on?(code)
......
...@@ -57,7 +57,7 @@ class Namespace < ActiveRecord::Base ...@@ -57,7 +57,7 @@ class Namespace < ActiveRecord::Base
'COALESCE(SUM(ps.storage_size), 0) AS storage_size', 'COALESCE(SUM(ps.storage_size), 0) AS storage_size',
'COALESCE(SUM(ps.repository_size), 0) AS repository_size', 'COALESCE(SUM(ps.repository_size), 0) AS repository_size',
'COALESCE(SUM(ps.lfs_objects_size), 0) AS lfs_objects_size', 'COALESCE(SUM(ps.lfs_objects_size), 0) AS lfs_objects_size',
'COALESCE(SUM(ps.build_artifacts_size), 0) AS build_artifacts_size', 'COALESCE(SUM(ps.build_artifacts_size), 0) AS build_artifacts_size'
) )
end end
......
...@@ -1095,7 +1095,7 @@ class Project < ActiveRecord::Base ...@@ -1095,7 +1095,7 @@ class Project < ActiveRecord::Base
namespace: namespace.name, namespace: namespace.name,
visibility_level: visibility_level, visibility_level: visibility_level,
path_with_namespace: path_with_namespace, path_with_namespace: path_with_namespace,
default_branch: default_branch, default_branch: default_branch
} }
# Backward compatibility # Backward compatibility
......
...@@ -52,7 +52,7 @@ class BambooService < CiService ...@@ -52,7 +52,7 @@ class BambooService < CiService
placeholder: 'Bamboo build plan key like KEY' }, placeholder: 'Bamboo build plan key like KEY' },
{ type: 'text', name: 'username', { type: 'text', name: 'username',
placeholder: 'A user with API access, if applicable' }, placeholder: 'A user with API access, if applicable' },
{ type: 'password', name: 'password' }, { type: 'password', name: 'password' }
] ]
end end
......
...@@ -39,7 +39,7 @@ class ChatNotificationService < Service ...@@ -39,7 +39,7 @@ class ChatNotificationService < Service
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" }, { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'text', name: 'username', placeholder: 'e.g. GitLab' }, { type: 'text', name: 'username', placeholder: 'e.g. GitLab' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_default_branch' }, { type: 'checkbox', name: 'notify_only_default_branch' }
] ]
end end
......
...@@ -47,7 +47,7 @@ class EmailsOnPushService < Service ...@@ -47,7 +47,7 @@ class EmailsOnPushService < Service
help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." }, help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." },
{ type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs", { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs",
help: "Don't include possibly sensitive code diffs in notification body." }, help: "Don't include possibly sensitive code diffs in notification body." },
{ type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }, { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }
] ]
end end
end end
...@@ -19,7 +19,7 @@ class ExternalWikiService < Service ...@@ -19,7 +19,7 @@ class ExternalWikiService < Service
def fields def fields
[ [
{ type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki' }, { type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki' }
] ]
end end
......
...@@ -37,7 +37,7 @@ class FlowdockService < Service ...@@ -37,7 +37,7 @@ class FlowdockService < Service
repo: project.repository.path_to_repo, repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}", repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s", commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s", diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s"
) )
end end
end end
...@@ -41,7 +41,7 @@ class HipchatService < Service ...@@ -41,7 +41,7 @@ class HipchatService < Service
placeholder: 'Leave blank for default (v2)' }, placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server', { type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' }, placeholder: 'Leave blank for default. https://hipchat.example.com' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' }
] ]
end end
......
...@@ -58,7 +58,7 @@ class IrkerService < Service ...@@ -58,7 +58,7 @@ class IrkerService < Service
' want to use a password, you have to omit the "#" on the channel). If you ' \ ' want to use a password, you have to omit the "#" on the channel). If you ' \
' specify a default IRC URI to prepend before each recipient, you can just ' \ ' specify a default IRC URI to prepend before each recipient, you can just ' \
' give a channel name.' }, ' give a channel name.' },
{ type: 'checkbox', name: 'colorize_messages' }, { type: 'checkbox', name: 'colorize_messages' }
] ]
end end
......
...@@ -90,7 +90,7 @@ class JenkinsDeprecatedService < CiService ...@@ -90,7 +90,7 @@ class JenkinsDeprecatedService < CiService
get_url = build_page(sha, ref).gsub("#{parsed_url.userinfo}@", "") get_url = build_page(sha, ref).gsub("#{parsed_url.userinfo}@", "")
auth = { auth = {
username: URI.decode(parsed_url.user), username: URI.decode(parsed_url.user),
password: URI.decode(parsed_url.password), password: URI.decode(parsed_url.password)
} }
response = HTTParty.get(get_url, verify: false, basic_auth: auth) response = HTTParty.get(get_url, verify: false, basic_auth: auth)
end end
......
...@@ -83,7 +83,7 @@ class JenkinsService < CiService ...@@ -83,7 +83,7 @@ class JenkinsService < CiService
help: 'The URL-friendly project name. Example: my_project_name' help: 'The URL-friendly project name. Example: my_project_name'
}, },
{ type: 'text', name: 'username' }, { type: 'text', name: 'username' },
{ type: 'password', name: 'password' }, { type: 'password', name: 'password' }
] ]
end end
end end
...@@ -149,7 +149,7 @@ class JiraService < IssueTrackerService ...@@ -149,7 +149,7 @@ class JiraService < IssueTrackerService
data = { data = {
user: { user: {
name: author.name, name: author.name,
url: resource_url(user_path(author)), url: resource_url(user_path(author))
}, },
project: { project: {
name: self.project.path_with_namespace, name: self.project.path_with_namespace,
......
...@@ -73,7 +73,7 @@ class KubernetesService < DeploymentService ...@@ -73,7 +73,7 @@ class KubernetesService < DeploymentService
{ type: 'textarea', { type: 'textarea',
name: 'ca_pem', name: 'ca_pem',
title: 'Custom CA bundle', title: 'Custom CA bundle',
placeholder: 'Certificate Authority bundle (PEM format)' }, placeholder: 'Certificate Authority bundle (PEM format)' }
] ]
end end
......
...@@ -35,7 +35,7 @@ class MicrosoftTeamsService < ChatNotificationService ...@@ -35,7 +35,7 @@ class MicrosoftTeamsService < ChatNotificationService
[ [
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" }, { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_default_branch' }, { type: 'checkbox', name: 'notify_only_default_branch' }
] ]
end end
......
...@@ -21,7 +21,7 @@ class MockCiService < CiService ...@@ -21,7 +21,7 @@ class MockCiService < CiService
[ [
{ type: 'text', { type: 'text',
name: 'mock_service_url', name: 'mock_service_url',
placeholder: 'http://localhost:4004' }, placeholder: 'http://localhost:4004' }
] ]
end end
......
...@@ -55,7 +55,7 @@ class PipelinesEmailService < Service ...@@ -55,7 +55,7 @@ class PipelinesEmailService < Service
name: 'recipients', name: 'recipients',
placeholder: 'Emails separated by comma' }, placeholder: 'Emails separated by comma' },
{ type: 'checkbox', { type: 'checkbox',
name: 'notify_only_broken_pipelines' }, name: 'notify_only_broken_pipelines' }
] ]
end end
......
...@@ -55,7 +55,7 @@ class PushoverService < Service ...@@ -55,7 +55,7 @@ class PushoverService < Service
['Pushover Echo (long)', 'echo'], ['Pushover Echo (long)', 'echo'],
['Up Down (long)', 'updown'], ['Up Down (long)', 'updown'],
['None (silent)', 'none'] ['None (silent)', 'none']
] }, ] }
] ]
end end
......
...@@ -55,7 +55,7 @@ class TeamcityService < CiService ...@@ -55,7 +55,7 @@ class TeamcityService < CiService
placeholder: 'Build configuration ID' }, placeholder: 'Build configuration ID' },
{ type: 'text', name: 'username', { type: 'text', name: 'username',
placeholder: 'A user with permissions to trigger a manual build' }, placeholder: 'A user with permissions to trigger a manual build' },
{ type: 'password', name: 'password' }, { type: 'password', name: 'password' }
] ]
end end
...@@ -78,7 +78,7 @@ class TeamcityService < CiService ...@@ -78,7 +78,7 @@ class TeamcityService < CiService
auth = { auth = {
username: username, username: username,
password: password, password: password
} }
branch = Gitlab::Git.ref_name(data[:ref]) branch = Gitlab::Git.ref_name(data[:ref])
......
...@@ -859,7 +859,7 @@ class Repository ...@@ -859,7 +859,7 @@ class Repository
actual_options = options.merge( actual_options = options.merge(
parents: [our_commit, their_commit], parents: [our_commit, their_commit],
tree: merge_index.write_tree(rugged), tree: merge_index.write_tree(rugged)
) )
commit_id = create_commit(actual_options) commit_id = create_commit(actual_options)
......
...@@ -39,7 +39,7 @@ class SentNotification < ActiveRecord::Base ...@@ -39,7 +39,7 @@ class SentNotification < ActiveRecord::Base
noteable_type: noteable.class.name, noteable_type: noteable.class.name,
noteable_id: noteable_id, noteable_id: noteable_id,
commit_id: commit_id, commit_id: commit_id
) )
create(attrs) create(attrs)
......
...@@ -153,18 +153,5 @@ class Snippet < ActiveRecord::Base ...@@ -153,18 +153,5 @@ class Snippet < ActiveRecord::Base
where(table[:content].matches(pattern)) where(table[:content].matches(pattern))
end end
def accessible_to(user)
return are_public unless user.present?
return all if user.admin?
where(
'visibility_level IN (:visibility_levels)
OR author_id = :author_id
OR project_id IN (:project_ids)',
visibility_levels: [Snippet::PUBLIC, Snippet::INTERNAL],
author_id: user.id,
project_ids: user.authorized_projects.select(:id))
end
end end
end end
...@@ -17,7 +17,7 @@ class ProjectSnippetPolicy < BasePolicy ...@@ -17,7 +17,7 @@ class ProjectSnippetPolicy < BasePolicy
can! :read_project_snippet can! :read_project_snippet
end end
if @subject.private? && @subject.project.team.member?(@user) if @subject.project.team.member?(@user)
can! :read_project_snippet can! :read_project_snippet
end end
end end
......
...@@ -31,9 +31,12 @@ class BuildEntity < Grape::Entity ...@@ -31,9 +31,12 @@ class BuildEntity < Grape::Entity
def detailed_status def detailed_status
build.detailed_status(request.current_user) build.detailed_status(request.current_user)
<<<<<<< HEAD
end end
def path_to(route, build) def path_to(route, build)
send("#{route}_path", build.project.namespace, build.project, build) send("#{route}_path", build.project.namespace, build.project, build)
=======
>>>>>>> origin/master
end end
end end
...@@ -39,7 +39,7 @@ class EnvironmentEntity < Grape::Entity ...@@ -39,7 +39,7 @@ class EnvironmentEntity < Grape::Entity
end end
expose :rollout_status_path, if: ->(environment, _) { environment.deployment_service_ready? } do |environment| expose :rollout_status_path, if: ->(environment, _) { environment.deployment_service_ready? } do |environment|
can?(request.user, :read_deploy_board, environment.project) && can?(request.current_user, :read_deploy_board, environment.project) &&
status_namespace_project_environment_path( status_namespace_project_environment_path(
environment.project.namespace, environment.project.namespace,
environment.project, environment.project,
......
...@@ -16,7 +16,7 @@ class AkismetService ...@@ -16,7 +16,7 @@ class AkismetService
created_at: DateTime.now, created_at: DateTime.now,
author: owner.name, author: owner.name,
author_email: owner.email, author_email: owner.email,
referrer: options[:referrer], referrer: options[:referrer]
} }
begin begin
......
...@@ -18,7 +18,7 @@ class AuditEventService ...@@ -18,7 +18,7 @@ class AuditEventService
author_name: author_name, author_name: author_name,
target_id: user_id, target_id: user_id,
target_type: "User", target_type: "User",
target_details: user_name, target_details: user_name
} }
when :create when :create
{ {
...@@ -27,7 +27,7 @@ class AuditEventService ...@@ -27,7 +27,7 @@ class AuditEventService
author_name: author_name, author_name: author_name,
target_id: user_id, target_id: user_id,
target_type: "User", target_type: "User",
target_details: user_name, target_details: user_name
} }
when :update when :update
{ {
...@@ -37,7 +37,7 @@ class AuditEventService ...@@ -37,7 +37,7 @@ class AuditEventService
author_name: author_name, author_name: author_name,
target_id: user_id, target_id: user_id,
target_type: "User", target_type: "User",
target_details: user_name, target_details: user_name
} }
end end
...@@ -56,7 +56,7 @@ class AuditEventService ...@@ -56,7 +56,7 @@ class AuditEventService
author_name: author_name, author_name: author_name,
target_id: key_title, target_id: key_title,
target_type: "DeployKey", target_type: "DeployKey",
target_details: key_title, target_details: key_title
} }
when :create when :create
{ {
...@@ -64,7 +64,7 @@ class AuditEventService ...@@ -64,7 +64,7 @@ class AuditEventService
author_name: author_name, author_name: author_name,
target_id: key_title, target_id: key_title,
target_type: "DeployKey", target_type: "DeployKey",
target_details: key_title, target_details: key_title
} }
end end
...@@ -76,7 +76,7 @@ class AuditEventService ...@@ -76,7 +76,7 @@ class AuditEventService
with: @details[:with], with: @details[:with],
target_id: @author.id, target_id: @author.id,
target_type: 'User', target_type: 'User',
target_details: @author.name, target_details: @author.name
} }
self self
......
...@@ -38,7 +38,7 @@ module Boards ...@@ -38,7 +38,7 @@ module Boards
attrs.merge!( attrs.merge!(
add_label_ids: add_label_ids, add_label_ids: add_label_ids,
remove_label_ids: remove_label_ids, remove_label_ids: remove_label_ids,
state_event: issue_state, state_event: issue_state
) )
end end
......
...@@ -10,18 +10,6 @@ module Geo ...@@ -10,18 +10,6 @@ module Geo
end end
def execute def execute
# When Geo customers upgrade to 9.0, the secondaries nodes that are
# enabled will start the backfilling process automatically. We need
# to populate the tracking database correctly for projects synced
# before the process being started or projects created during the
# backfilling. Otherwise, the query to retrieve the projects will
# always return the same projects because they don't have entries
# in the tracking database
if backfilled?
update_registry(DateTime.now, DateTime.now)
return
end
try_obtain_lease do try_obtain_lease do
log('Started repository sync') log('Started repository sync')
started_at, finished_at = fetch_repositories started_at, finished_at = fetch_repositories
...@@ -76,7 +64,6 @@ module Geo ...@@ -76,7 +64,6 @@ module Geo
def try_obtain_lease def try_obtain_lease
log('Trying to obtain lease to sync repository') log('Trying to obtain lease to sync repository')
repository_lease = Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT).try_obtain repository_lease = Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT).try_obtain
if repository_lease.nil? if repository_lease.nil?
...@@ -93,25 +80,7 @@ module Geo ...@@ -93,25 +80,7 @@ module Geo
Gitlab::ExclusiveLease.cancel(lease_key, repository_lease) Gitlab::ExclusiveLease.cancel(lease_key, repository_lease)
end end
def backfilled?
return false unless project.repository.exists?
return false if project.repository.exists? && project.repository.empty?
return false if failed_registry_exists?
true
end
def failed_registry_exists?
Geo::ProjectRegistry.failed.where(project_id: project_id).any?
end
def synced_registry_exists?
Geo::ProjectRegistry.synced.where(project_id: project_id).any?
end
def update_registry(started_at, finished_at) def update_registry(started_at, finished_at)
return if synced_registry_exists?
log('Updating registry information') log('Updating registry information')
registry = Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id) registry = Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id)
registry.last_repository_synced_at = started_at registry.last_repository_synced_at = started_at
......
module Geo
class RepositoryUpdateService
attr_reader :project, :clone_url, :logger
LEASE_TIMEOUT = 1.hour.freeze
LEASE_KEY_PREFIX = 'geo_repository_fetch'.freeze
def initialize(project, clone_url, logger = Rails.logger)
@project = project
@clone_url = clone_url
@logger = logger
end
def execute
try_obtain_lease do
project.create_repository unless project.repository_exists?
project.repository.after_create if project.empty_repo?
project.repository.fetch_geo_mirror(clone_url)
project.repository.expire_all_method_caches
project.repository.expire_branch_cache
project.repository.expire_content_cache
end
rescue Gitlab::Shell::Error => e
logger.error "Error fetching repository for project #{project.path_with_namespace}: #{e}"
end
private
def try_obtain_lease
log('Trying to obtain lease to sync repository')
repository_lease = Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT).try_obtain
unless repository_lease.present?
log('Could not obtain lease to sync repository')
return
end
begin
yield
ensure
log('Releasing leases to sync repository')
Gitlab::ExclusiveLease.cancel(lease_key, repository_lease)
end
end
def lease_key
@lease_key ||= "#{LEASE_KEY_PREFIX}:#{project.id}"
end
def log(message)
logger.info("#{self.class.name}: #{message} for project #{project.path_with_namespace} (#{project.id})")
end
end
end
...@@ -2,7 +2,7 @@ module Geo ...@@ -2,7 +2,7 @@ module Geo
class ScheduleRepoFetchService class ScheduleRepoFetchService
def initialize(params) def initialize(params)
@project_id = params[:project_id] @project_id = params[:project_id]
@remote_url = params[:remote_url] @remote_url = params[:project][:git_ssh_url]
end end
def execute def execute
......
...@@ -321,7 +321,7 @@ class NotificationService ...@@ -321,7 +321,7 @@ class NotificationService
recipients ||= NotificationRecipientService.new(pipeline.project).build_pipeline_recipients( recipients ||= NotificationRecipientService.new(pipeline.project).build_pipeline_recipients(
pipeline, pipeline,
pipeline.user, pipeline.user,
action: pipeline.status, action: pipeline.status
).map(&:notification_email) ).map(&:notification_email)
if recipients.any? if recipients.any?
......
...@@ -27,7 +27,7 @@ module Projects ...@@ -27,7 +27,7 @@ module Projects
{ {
domain: domain.domain, domain: domain.domain,
certificate: domain.certificate, certificate: domain.certificate,
key: domain.key, key: domain.key
} }
end end
end end
......
module Search module Search
class SnippetService class SnippetService
include Gitlab::CurrentSettings
attr_accessor :current_user, :params attr_accessor :current_user, :params
def initialize(user, params) def initialize(user, params)
...@@ -8,13 +7,9 @@ module Search ...@@ -8,13 +7,9 @@ module Search
end end
def execute def execute
if current_application_settings.elasticsearch_search? snippets = SnippetsFinder.new(current_user).execute
Gitlab::Elastic::SnippetSearchResults.new(current_user,
params[:search]) Gitlab::SnippetSearchResults.new(snippets, params[:search])
else
snippets = Snippet.accessible_to(current_user)
Gitlab::SnippetSearchResults.new(snippets, params[:search])
end
end end
def scope def scope
......
...@@ -51,7 +51,7 @@ class SystemHooksService ...@@ -51,7 +51,7 @@ class SystemHooksService
path: model.path, path: model.path,
group_id: model.id, group_id: model.id,
owner_name: owner.respond_to?(:name) ? owner.name : nil, owner_name: owner.respond_to?(:name) ? owner.name : nil,
owner_email: owner.respond_to?(:email) ? owner.email : nil, owner_email: owner.respond_to?(:email) ? owner.email : nil
) )
when GroupMember when GroupMember
data.merge!(group_member_data(model)) data.merge!(group_member_data(model))
...@@ -113,7 +113,7 @@ class SystemHooksService ...@@ -113,7 +113,7 @@ class SystemHooksService
user_name: model.user.name, user_name: model.user.name,
user_email: model.user.email, user_email: model.user.email,
user_id: model.user.id, user_id: model.user.id,
group_access: model.human_access, group_access: model.human_access
} }
end end
end end
...@@ -18,19 +18,26 @@ ...@@ -18,19 +18,26 @@
or adding ssh key. But you can also enable extra triggers like Push events. or adding ssh key. But you can also enable extra triggers like Push events.
.prepend-top-default .prepend-top-default
= form.check_box :repository_update_events, class: 'pull-left'
.prepend-left-20
= form.label :repository_update_events, class: 'list-label' do
%strong Repository update events
%p.light
This URL will be triggered when repository is updated
%div
= form.check_box :push_events, class: 'pull-left' = form.check_box :push_events, class: 'pull-left'
.prepend-left-20 .prepend-left-20
= form.label :push_events, class: 'list-label' do = form.label :push_events, class: 'list-label' do
%strong Push events %strong Push events
%p.light %p.light
This url will be triggered by a push to the repository This URL will be triggered for each branch updated to the repository
%div %div
= form.check_box :tag_push_events, class: 'pull-left' = form.check_box :tag_push_events, class: 'pull-left'
.prepend-left-20 .prepend-left-20
= form.label :tag_push_events, class: 'list-label' do = form.label :tag_push_events, class: 'list-label' do
%strong Tag push events %strong Tag push events
%p.light %p.light
This url will be triggered when a new tag is pushed to the repository This URL will be triggered when a new tag is pushed to the repository
.form-group .form-group
= form.label :enable_ssl_verification, 'SSL verification', class: 'control-label checkbox' = form.label :enable_ssl_verification, 'SSL verification', class: 'control-label checkbox'
.col-sm-10 .col-sm-10
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
= link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm' = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
.monospace= hook.url .monospace= hook.url
%div %div
- %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger| - %w(repository_update_events push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger|
- if hook.send(trigger) - if hook.send(trigger)
%span.label.label-gray= trigger.titleize %span.label.label-gray= trigger.titleize
%span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'} %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
...@@ -10,4 +10,4 @@ ...@@ -10,4 +10,4 @@
- else - else
:plain :plain
job = $("tr#repo_#{@repo_id}") job = $("tr#repo_#{@repo_id}")
job.find(".import-actions").html("<i class='fa fa-exclamation-circle'></i> Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}") job.find(".import-actions").html("<i class='fa fa-exclamation-circle'></i> Error saving project: #{escape_javascript(h(@project.errors.full_messages.join(',')))}")
...@@ -17,11 +17,13 @@ ...@@ -17,11 +17,13 @@
.help-block.text-danger.js-branch-name-error .help-block.text-danger.js-branch-name-error
.form-group .form-group
= label_tag :ref, 'Create from', class: 'control-label' = label_tag :ref, 'Create from', class: 'control-label'
.col-sm-10.dropdown.create-from .col-sm-10.create-from
= hidden_field_tag :ref, default_ref .dropdown
= button_tag type: 'button', title: default_ref, class: 'dropdown-toggle form-control js-branch-select', required: true, data: { toggle: 'dropdown', selected: default_ref, field_name: 'ref' } do = hidden_field_tag :ref, default_ref
.text-left.dropdown-toggle-text= default_ref = button_tag type: 'button', title: default_ref, class: 'dropdown-menu-toggle wide form-control js-branch-select', required: true, data: { toggle: 'dropdown', selected: default_ref, field_name: 'ref' } do
= render 'shared/ref_dropdown', dropdown_class: 'wide' .text-left.dropdown-toggle-text= default_ref
= icon('chevron-down')
= render 'shared/ref_dropdown', dropdown_class: 'wide'
.help-block Existing branch name, tag, or commit SHA .help-block Existing branch name, tag, or commit SHA
.form-actions .form-actions
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3 = button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
.panel-body .panel-body
%pre %pre
:preserve :preserve
#{sanitize_repo_path(@project, @project.import_error)} #{h(sanitize_repo_path(@project, @project.import_error))}
= form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f| = form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f|
= render "shared/import_form", f: f = render "shared/import_form", f: f
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
.panel-body .panel-body
%pre %pre
:preserve :preserve
#{@project.import_error.try(:strip)} #{h(@project.import_error.try(:strip))}
.form-group .form-group
= f.check_box :mirror, class: "pull-left" = f.check_box :mirror, class: "pull-left"
.prepend-left-20 .prepend-left-20
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
.panel-body .panel-body
%pre %pre
:preserve :preserve
#{@remote_mirror.last_error.strip} #{h(@remote_mirror.last_error.strip)}
= f.fields_for :remote_mirrors, @remote_mirror do |rm_form| = f.fields_for :remote_mirrors, @remote_mirror do |rm_form|
.form-group .form-group
= rm_form.check_box :enabled, class: "pull-left" = rm_form.check_box :enabled, class: "pull-left"
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
%h3 Clone your wiki %h3 Clone your wiki
%pre.dark %pre.dark
:preserve :preserve
git clone #{ content_tag(:span, default_url_to_repo(@project_wiki), class: 'clone')} git clone #{ content_tag(:span, h(default_url_to_repo(@project_wiki)), class: 'clone')}
cd #{h @project_wiki.path} cd #{h @project_wiki.path}
%h3 Start Gollum and edit locally %h3 Start Gollum and edit locally
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
- if note.system - if note.system
%span.system-note-message %span.system-note-message
= note.redacted_note_html = note.redacted_note_html
.original-note-content.hidden
= note.note
%a{ href: "##{dom_id(note)}" } %a{ href: "##{dom_id(note)}" }
= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago') = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago')
- unless note.system? - unless note.system?
......
...@@ -2,15 +2,18 @@ class GeoBackfillWorker ...@@ -2,15 +2,18 @@ class GeoBackfillWorker
include Sidekiq::Worker include Sidekiq::Worker
include CronjobQueue include CronjobQueue
RUN_TIME = 5.minutes.to_i.freeze RUN_TIME = 5.minutes.to_i
BATCH_SIZE = 100.freeze BATCH_SIZE = 100
LAST_SYNC_INTERVAL = 24.hours
def perform def perform
return unless Gitlab::Geo.configured? return unless Gitlab::Geo.configured?
return unless Gitlab::Geo.primary_node.present? return unless Gitlab::Geo.primary_node.present?
start_time = Time.now start_time = Time.now
project_ids = find_project_ids project_ids_not_synced = find_project_ids_not_synced
project_ids_updated_recently = find_synced_project_ids_updated_recently
project_ids = interleave(project_ids_not_synced, project_ids_updated_recently)
logger.info "Started Geo backfilling for #{project_ids.length} project(s)" logger.info "Started Geo backfilling for #{project_ids.length} project(s)"
...@@ -38,12 +41,34 @@ class GeoBackfillWorker ...@@ -38,12 +41,34 @@ class GeoBackfillWorker
private private
def find_project_ids def find_project_ids_not_synced
Project.where.not(id: Geo::ProjectRegistry.synced.pluck(:project_id)) Project.where.not(id: Geo::ProjectRegistry.synced.pluck(:project_id))
.limit(BATCH_SIZE) .limit(BATCH_SIZE)
.pluck(:id) .pluck(:id)
end end
def find_synced_project_ids_updated_recently
Geo::ProjectRegistry.where(project_id: find_project_ids_updated_recently)
.where('last_repository_synced_at <= ?', LAST_SYNC_INTERVAL.ago)
.order(last_repository_synced_at: :asc)
.limit(BATCH_SIZE)
.pluck(:project_id)
end
def find_project_ids_updated_recently
Project.where(id: Geo::ProjectRegistry.synced.pluck(:project_id))
.where('last_repository_updated_at >= ?', LAST_SYNC_INTERVAL.ago)
.pluck(:id)
end
def interleave(first, second)
if first.length >= second.length
first.zip(second)
else
second.zip(first).map(&:reverse)
end.flatten(1).compact.take(BATCH_SIZE)
end
def over_time?(start_time) def over_time?(start_time)
Time.now - start_time >= RUN_TIME Time.now - start_time >= RUN_TIME
end end
......
...@@ -8,14 +8,6 @@ class GeoRepositoryFetchWorker ...@@ -8,14 +8,6 @@ class GeoRepositoryFetchWorker
def perform(project_id, clone_url) def perform(project_id, clone_url)
project = Project.find(project_id) project = Project.find(project_id)
Geo::RepositoryUpdateService.new(project, clone_url, logger).execute
project.create_repository unless project.repository_exists?
project.repository.after_create if project.empty_repo?
project.repository.fetch_geo_mirror(clone_url)
project.repository.expire_all_method_caches
project.repository.expire_branch_cache
project.repository.expire_content_cache
rescue Gitlab::Shell::Error => e
logger.error "Error fetching repository for project #{project.path_with_namespace}: #{e}"
end end
end end
...@@ -23,26 +23,33 @@ class PostReceive ...@@ -23,26 +23,33 @@ class PostReceive
# Triggers repository update on secondary nodes when Geo is enabled # Triggers repository update on secondary nodes when Geo is enabled
Gitlab::Geo.notify_wiki_update(post_received.project) if Gitlab::Geo.enabled? Gitlab::Geo.notify_wiki_update(post_received.project) if Gitlab::Geo.enabled?
else else
# TODO: gitlab-org/gitlab-ce#26325. Remove this. process_project_changes(post_received)
if Gitlab::Geo.enabled? process_repository_update(post_received)
hook_data = { end
event_name: 'repository_update', end
project_id: post_received.project.id,
project: post_received.project.hook_attrs, def process_repository_update(post_received)
remote_url: post_received.project.ssh_url_to_repo changes = []
} refs = Set.new
SystemHooksService.new.execute_hooks(hook_data, :repository_update_hooks) post_received.changes_refs do |oldrev, newrev, ref|
@user ||= post_received.identify(newrev)
unless @user
log("Triggered hook for non-existing user \"#{post_received.identifier}\"")
return false
end end
process_project_changes(post_received) changes << Gitlab::DataBuilder::Repository.single_change(oldrev, newrev, ref)
refs << ref
end end
hook_data = Gitlab::DataBuilder::Repository.update(post_received.project, @user, changes, refs.to_a)
SystemHooksService.new.execute_hooks(hook_data, :repository_update_hooks)
end end
def process_project_changes(post_received) def process_project_changes(post_received)
post_received.changes.each do |change| post_received.changes_refs do |oldrev, newrev, ref|
oldrev, newrev, ref = change.strip.split(' ')
@user ||= post_received.identify(newrev) @user ||= post_received.identify(newrev)
unless @user unless @user
......
...@@ -8,7 +8,7 @@ module RepositoryCheck ...@@ -8,7 +8,7 @@ module RepositoryCheck
Project.select(:id).find_in_batches(batch_size: 100) do |batch| Project.select(:id).find_in_batches(batch_size: 100) do |batch|
Project.where(id: batch.map(&:id)).update_all( Project.where(id: batch.map(&:id)).update_all(
last_repository_check_failed: nil, last_repository_check_failed: nil,
last_repository_check_at: nil, last_repository_check_at: nil
) )
end end
end end
......
...@@ -7,7 +7,7 @@ module RepositoryCheck ...@@ -7,7 +7,7 @@ module RepositoryCheck
project = Project.find(project_id) project = Project.find(project_id)
project.update_columns( project.update_columns(
last_repository_check_failed: !check(project), last_repository_check_failed: !check(project),
last_repository_check_at: Time.now, last_repository_check_at: Time.now
) )
end end
......
---
title: Geo: Improve Repository Sync (with new SystemHook)
merge_request: 1789
author:
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment