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:
# This cop checks for trailing comma in array and hash literals.
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.
Style/UnneededCapitalW:
......
......@@ -369,13 +369,6 @@ Style/SymbolProc:
Style/TernaryParentheses:
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
# Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables.
......
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)
- No changes.
......@@ -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.
- 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)
- 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.
- [Elasticsearch] More efficient search.
- 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)
- No changes.
......
......@@ -623,7 +623,7 @@ GitLabDropdown = (function() {
var link = document.createElement('a');
link.href = url;
link.innerHTML = text;
link.textContent = text;
if (selected) {
link.className = 'is-active';
......
......@@ -24,7 +24,7 @@ const normalizeNewlines = function(str) {
(function() {
this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const REGEX_SLASH_COMMANDS = /\/\w+/g;
const REGEX_SLASH_COMMANDS = /^\/\w+/gm;
Notes.interval = null;
......
......@@ -388,9 +388,9 @@
content: '';
position: absolute;
top: 48%;
left: -48px;
left: -44px;
border-top: 2px solid $border-color;
width: 48px;
width: 44px;
height: 1px;
}
}
......@@ -490,7 +490,11 @@
color: $gl-text-color-secondary;
// Action Icons in big pipeline-graph nodes
<<<<<<< HEAD
> div > .ci-action-icon-container .ci-action-icon-wrapper {
=======
.ci-action-icon-container .ci-action-icon-wrapper {
>>>>>>> origin/master
height: 30px;
width: 30px;
background: $white-light;
......@@ -515,7 +519,11 @@
}
}
<<<<<<< HEAD
> div > .ci-action-icon-container {
=======
.ci-action-icon-container {
>>>>>>> origin/master
position: absolute;
right: 5px;
top: 5px;
......@@ -545,7 +553,11 @@
}
}
<<<<<<< HEAD
> div > .build-content {
=======
.build-content {
>>>>>>> origin/master
display: inline-block;
padding: 8px 10px 9px;
width: 100%;
......
......@@ -174,7 +174,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:shared_runners_minutes,
:minimum_mirror_sync_time,
:geo_status_timeout,
:elasticsearch_experimental_indexer,
:elasticsearch_experimental_indexer
]
end
end
......@@ -60,6 +60,7 @@ class Admin::HooksController < Admin::ApplicationController
:enable_ssl_verification,
:push_events,
:tag_push_events,
:repository_update_events,
:token,
:url
)
......
......@@ -45,7 +45,7 @@ class AutocompleteController < ApplicationController
no_project = {
id: 0,
name_with_namespace: 'No project',
name_with_namespace: 'No project'
}
projects.unshift(no_project) unless params[:offset_id].present?
......
......@@ -23,7 +23,7 @@ module LfsRequest
render(
json: {
message: 'Git LFS is not enabled on this GitLab server, contact your admin.',
documentation_url: help_url,
documentation_url: help_url
},
status: 501
)
......@@ -48,7 +48,7 @@ module LfsRequest
render(
json: {
message: 'Access forbidden. Check your access level.',
documentation_url: help_url,
documentation_url: help_url
},
content_type: "application/vnd.git-lfs+json",
status: 403
......@@ -59,7 +59,7 @@ module LfsRequest
render(
json: {
message: 'Not found.',
documentation_url: help_url,
documentation_url: help_url
},
content_type: "application/vnd.git-lfs+json",
status: 404
......@@ -123,7 +123,7 @@ module LfsRequest
render(
json: {
message: Gitlab::RepositorySizeError.new(project).push_error(@exceeded_limit),
documentation_url: help_url,
documentation_url: help_url
},
content_type: "application/vnd.git-lfs+json",
status: 406
......
class Dashboard::SnippetsController < Dashboard::ApplicationController
def index
@snippets = SnippetsFinder.new.execute(
@snippets = SnippetsFinder.new(
current_user,
filter: :by_user,
user: current_user,
author: current_user,
scope: params[:scope]
)
).execute
@snippets = @snippets.page(params[:page])
end
end
class Explore::GroupsController < Explore::ApplicationController
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.sort(@sort = params[:sort])
@groups = @groups.page(params[:page])
......
class Explore::SnippetsController < Explore::ApplicationController
def index
@snippets = SnippetsFinder.new.execute(current_user, filter: :all)
@snippets = SnippetsFinder.new(current_user).execute
@snippets = @snippets.page(params[:page])
end
end
......@@ -64,7 +64,7 @@ class GroupsController < Groups::ApplicationController
end
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?
end
......
......@@ -5,7 +5,7 @@ class HealthController < ActionController::Base
CHECKS = [
Gitlab::HealthChecks::DbCheck,
Gitlab::HealthChecks::RedisCheck,
Gitlab::HealthChecks::FsShardsCheck,
Gitlab::HealthChecks::FsShardsCheck
].freeze
def readiness
......
......@@ -4,7 +4,7 @@ class JwtController < ApplicationController
before_action :authenticate_project_or_user
SERVICES = {
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService,
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService
}.freeze
def auth
......
......@@ -33,7 +33,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:color_scheme_id,
:layout,
:dashboard,
:project_view,
:project_view
)
end
end
......@@ -6,7 +6,7 @@ class Projects::DeploymentsController < Projects::ApplicationController
deployments = environment.deployments.reorder(created_at: :desc)
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) }
end
......
......@@ -143,7 +143,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
if rollout_status.nil?
render body: nil, status: 204 # no result yet
else
serializer = RolloutStatusSerializer.new(project: @project, user: @current_user)
serializer = RolloutStatusSerializer.new(project: @project, current_user: @current_user)
render json: serializer.represent(rollout_status)
end
end
......
......@@ -217,7 +217,7 @@ class Projects::IssuesController < Projects::ApplicationController
description_text: @issue.description,
task_status: @issue.task_status,
issue_number: @issue.iid,
updated_at: @issue.updated_at,
updated_at: @issue.updated_at
}
end
......@@ -277,7 +277,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue_params
params.require(:issue).permit(
: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
......
......@@ -22,7 +22,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
render(
json: {
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
)
......@@ -55,7 +55,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
else
object[:error] = {
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
......
......@@ -44,7 +44,7 @@ class Projects::PipelinesController < Projects::ApplicationController
all: @pipelines_count,
running: @running_count,
pending: @pending_count,
finished: @finished_count,
finished: @finished_count
}
}
end
......
......@@ -23,12 +23,11 @@ class Projects::SnippetsController < Projects::ApplicationController
respond_to :html
def index
@snippets = SnippetsFinder.new.execute(
@snippets = SnippetsFinder.new(
current_user,
filter: :by_project,
project: @project,
scope: params[:scope]
)
).execute
@snippets = @snippets.page(params[:page])
if @snippets.out_of_range? && @snippets.total_pages != 0
redirect_to namespace_project_snippets_path(page: @snippets.total_pages)
......
......@@ -48,7 +48,7 @@ class Projects::TreeController < Projects::ApplicationController
@dir_name = File.join(@path, params[:dir_name])
@commit_params = {
file_path: @dir_name,
commit_message: params[:commit_message],
commit_message: params[:commit_message]
}
end
end
......@@ -221,7 +221,7 @@ class ProjectsController < Projects::ApplicationController
branches = BranchesFinder.new(@repository, params).execute.map(&:name)
options = {
'Branches' => branches.take(100),
'Branches' => branches.take(100)
}
unless @repository.tag_count.zero?
......
......@@ -27,12 +27,8 @@ class SnippetsController < ApplicationController
return render_404 unless @user
@snippets = SnippetsFinder.new.execute(current_user, {
filter: :by_user,
user: @user,
scope: params[:scope]
})
.page(params[:page])
@snippets = SnippetsFinder.new(current_user, author: @user, scope: params[:scope])
.execute.page(params[:page])
render 'index'
else
......@@ -103,20 +99,20 @@ class SnippetsController < ApplicationController
protected
def snippet
@snippet ||= if current_user
PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
current_user.id,
[Snippet::PUBLIC, Snippet::INTERNAL]).
find(params[:id])
else
PersonalSnippet.find(params[:id])
end
@snippet ||= PersonalSnippet.find_by(id: params[:id])
end
alias_method :awardable, :snippet
alias_method :spammable, :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
def authorize_update_snippet!
......
......@@ -128,12 +128,11 @@ class UsersController < ApplicationController
end
def load_snippets
@snippets = SnippetsFinder.new.execute(
@snippets = SnippetsFinder.new(
current_user,
filter: :by_user,
user: user,
author: user,
scope: params[:scope]
).page(params[:page])
).execute.page(params[:page])
end
def projects_for_current_user
......
class GroupsFinder < UnionFinder
def execute(current_user = nil)
segments = all_groups(current_user)
def initialize(current_user = nil, params = {})
@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
private
def all_groups(current_user)
attr_reader :current_user, :params
def all_groups
groups = []
groups << current_user.authorized_groups if current_user
......@@ -15,4 +21,10 @@ class GroupsFinder < UnionFinder
groups
end
def by_parent(groups)
return groups unless params[:parent]
groups.where(parent: params[:parent])
end
end
......@@ -67,7 +67,7 @@ class NotesFinder
when "merge_request"
MergeRequestsFinder.new(@current_user, project_id: @project.id).execute
when "snippet", "project_snippet"
SnippetsFinder.new.execute(@current_user, filter: :by_project, project: @project)
SnippetsFinder.new(@current_user, project: @project).execute
when "personal_snippet"
PersonalSnippet.all
else
......
class SnippetsFinder
def execute(current_user, params = {})
filter = params[:filter]
user = params.fetch(:user, current_user)
case filter
when :all then
snippets(current_user).fresh
when :public then
Snippet.are_public.fresh
when :by_user then
by_user(current_user, user, params[:scope])
when :by_project
by_project(current_user, params[:project], params[:scope])
end
class SnippetsFinder < UnionFinder
attr_accessor :current_user, :params
def initialize(current_user, params = {})
@current_user = current_user
@params = params
end
def execute
items = init_collection
items = by_project(items)
items = by_author(items)
items = by_visibility(items)
items.fresh
end
private
def snippets(current_user)
if current_user
Snippet.public_and_internal
else
# Not authenticated
#
# Return only:
# public snippets
Snippet.are_public
end
def init_collection
items = Snippet.all
accessible(items)
end
def by_user(current_user, user, scope)
snippets = user.snippets.fresh
def accessible(items)
segments = []
segments << items.public_to_user(current_user)
segments << authorized_to_user(items) if current_user
if current_user
include_private = user == current_user
by_scope(snippets, scope, include_private)
else
snippets.are_public
end
find_union(segments, Snippet)
end
def by_project(current_user, project, scope)
snippets = project.snippets.fresh
def authorized_to_user(items)
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
include_private = project.team.member?(current_user) || current_user.admin_or_auditor?
by_scope(snippets, scope, include_private)
else
snippets.are_public
end
def by_visibility(items)
visibility = params[:visibility] || visibility_from_scope
return items unless visibility
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
def by_scope(snippets, scope = nil, include_private = false)
case scope.to_s
def visibility_from_scope
case params[:scope].to_s
when 'are_private'
include_private ? snippets.are_private : Snippet.none
Snippet::PRIVATE
when 'are_internal'
snippets.are_internal
Snippet::INTERNAL
when 'are_public'
snippets.are_public
Snippet::PUBLIC
else
include_private ? snippets : snippets.public_and_internal
nil
end
end
end
......@@ -98,7 +98,7 @@ module DiffHelper
[
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
end
......
......@@ -12,7 +12,7 @@ module EmailsHelper
"action" => {
"@type" => "ViewAction",
"name" => name,
"url" => url,
"url" => url
}
}
......
......@@ -41,7 +41,7 @@ module EventsHelper
link_opts = {
class: "event-filter-link",
id: "#{key}_event_filter",
title: "Filter by #{tooltip.downcase}",
title: "Filter by #{tooltip.downcase}"
}
content_tag :li, class: active do
......
......@@ -10,7 +10,7 @@ module ExploreHelper
personal: params[:personal],
archived: params[:archived],
shared: params[:shared],
namespace_id: params[:namespace_id],
namespace_id: params[:namespace_id]
}
options = exist_opts.merge(options).delete_if { |key, value| value.blank? }
......
......@@ -32,7 +32,7 @@ module MarkupHelper
context = {
project: @project,
current_user: (current_user if defined?(current_user)),
pipeline: :single_line,
pipeline: :single_line
}
gfm_body = Banzai.render(body, context)
......@@ -116,13 +116,13 @@ module MarkupHelper
if gitlab_markdown?(file_name)
markdown_unsafe(text, context)
elsif asciidoc?(file_name)
asciidoc_unsafe(text)
asciidoc_unsafe(text, context)
elsif plain?(file_name)
content_tag :pre, class: 'plain-readme' do
text
end
else
other_markup_unsafe(file_name, text)
other_markup_unsafe(file_name, text, context)
end
rescue RuntimeError
simple_format(text)
......@@ -217,12 +217,12 @@ module MarkupHelper
Banzai.render(text, context)
end
def asciidoc_unsafe(text)
Gitlab::Asciidoc.render(text)
def asciidoc_unsafe(text, context = {})
Gitlab::Asciidoc.render(text, context)
end
def other_markup_unsafe(file_name, text)
Gitlab::OtherMarkup.render(file_name, text)
def other_markup_unsafe(file_name, text, context = {})
Gitlab::OtherMarkup.render(file_name, text, context)
end
def prepare_for_rendering(html, context = {})
......
......@@ -54,7 +54,7 @@ module MergeRequestsHelper
source_project_id: merge_request.source_project_id,
target_project_id: merge_request.target_project_id,
source_branch: merge_request.source_branch,
target_branch: merge_request.target_branch,
target_branch: merge_request.target_branch
},
change_branches: true
)
......
......@@ -19,7 +19,7 @@ module NotesHelper
id: noteable.id,
class: noteable.class.name,
resources: noteable.class.table_name,
project_id: noteable.project.id,
project_id: noteable.project.id
}.to_json
end
......@@ -34,7 +34,7 @@ module NotesHelper
data = {
line_code: line_code,
line_type: line_type,
line_type: line_type
}
if @use_legacy_diff_notes
......
......@@ -50,7 +50,7 @@ module SearchHelper
{ category: "Settings", label: "User settings", url: profile_path },
{ category: "Settings", label: "SSH Keys", url: profile_keys_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
......@@ -65,7 +65,7 @@ module SearchHelper
{ 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: "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
......@@ -84,7 +84,7 @@ module SearchHelper
{ 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: "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
[]
......
......@@ -84,7 +84,7 @@ module SelectsHelper
current_user: opts[:current_user] || false,
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
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
......@@ -60,7 +60,7 @@ module SortingHelper
sort_value_due_date_soon => sort_title_due_date_soon,
sort_value_due_date_later => sort_title_due_date_later,
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
......
module SubmoduleHelper
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
def submodule_links(submodule_item, ref = nil, repository = @repository)
url = repository.submodule_url_for(ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
namespace = $1
project = $2
project.chomp!('.git')
if url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
namespace, project = $1, $2
project.sub!(/\.git\z/, '')
if self_url?(url, namespace, project)
return namespace_project_path(namespace, project),
namespace_project_tree_path(namespace, project,
submodule_item.id)
elsif relative_self_url?(url)
relative_self_links(url, submodule_item.id)
elsif github_dot_com_url?(url)
standard_links('github.com', namespace, project, submodule_item.id)
elsif gitlab_dot_com_url?(url)
standard_links('gitlab.com', namespace, project, submodule_item.id)
if self_url?(url, namespace, project)
[namespace_project_path(namespace, project),
namespace_project_tree_path(namespace, project, submodule_item.id)]
elsif relative_self_url?(url)
relative_self_links(url, submodule_item.id)
elsif github_dot_com_url?(url)
standard_links('github.com', namespace, project, submodule_item.id)
elsif gitlab_dot_com_url?(url)
standard_links('gitlab.com', namespace, project, submodule_item.id)
else
[sanitize_submodule_url(url), nil]
end
else
return url, nil
[sanitize_submodule_url(url), nil]
end
end
......@@ -73,4 +75,16 @@ module SubmoduleHelper
namespace_project_tree_path(namespace, base, commit)
]
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
......@@ -63,7 +63,7 @@ module TodosHelper
project_id: params[:project_id],
author_id: params[:author_id],
type: params[:type],
action_id: params[:action_id],
action_id: params[:action_id]
}
end
......
......@@ -318,7 +318,7 @@ class ApplicationSetting < ActiveRecord::Base
aws: elasticsearch_aws,
aws_access_key: elasticsearch_aws_access_key,
aws_secret_access_key: elasticsearch_aws_secret_access_key,
aws_region: elasticsearch_aws_region,
aws_region: elasticsearch_aws_region
}
end
......
......@@ -33,7 +33,7 @@ class Blob < SimpleDelegator
BlobViewer::PDF,
BlobViewer::BinarySTL,
BlobViewer::TextSTL,
BlobViewer::TextSTL
].freeze
BINARY_VIEWERS = RICH_VIEWERS.select(&:binary?).freeze
......
......@@ -49,7 +49,7 @@ class Commit
def max_diff_options
{
max_files: DIFF_HARD_LIMIT_FILES,
max_lines: DIFF_HARD_LIMIT_LINES,
max_lines: DIFF_HARD_LIMIT_LINES
}
end
......
......@@ -39,7 +39,7 @@ class DiffDiscussion < Discussion
def reply_attributes
super.merge(
original_position: original_position.to_json,
position: position.to_json,
position: position.to_json
)
end
end
......@@ -62,7 +62,7 @@ class Environment < ActiveRecord::Base
def predefined_variables
[
{ 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
......
......@@ -159,8 +159,9 @@ class GeoNode < ActiveRecord::Base
self.build_system_hook if system_hook.nil?
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.push_events = true
self.system_hook.tag_push_events = true
self.system_hook.push_events = false
self.system_hook.tag_push_events = false
self.system_hook.repository_update_events = true
end
def expire_cache!
......
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)
Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name)
end
def self.repository_update_hooks
GeoNode.where(primary: false).map(&:system_hook)
end
end
......@@ -10,6 +10,7 @@ class WebHook < ActiveRecord::Base
default_value_for :tag_push_events, false
default_value_for :build_events, false
default_value_for :pipeline_events, false
default_value_for :repository_update_events, false
default_value_for :enable_ssl_verification, true
scope :push_hooks, -> { where(push_events: true) }
......@@ -31,7 +32,7 @@ class WebHook < ActiveRecord::Base
post_url = url.gsub("#{parsed_url.userinfo}@", '')
auth = {
username: CGI.unescape(parsed_url.user),
password: CGI.unescape(parsed_url.password),
password: CGI.unescape(parsed_url.password)
}
response = WebHook.post(post_url,
body: data.to_json,
......
......@@ -76,7 +76,7 @@ class Key < ActiveRecord::Base
GitlabShellWorker.perform_async(
:remove_key,
shell_id,
key,
key
)
end
......
class License < ActiveRecord::Base
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 :check_users_limit, if: :new_record?, unless: :validate_with_trueup?
validate :check_trueup, unless: :persisted?, if: :validate_with_trueup?
......@@ -14,6 +32,10 @@ class License < ActiveRecord::Base
scope :previous, -> { order(created_at: :desc).offset(1) }
class << self
def features_for_plan(plan)
FEATURES_BY_PLAN.fetch(plan, []).reduce({}, :merge)
end
def current
if RequestStore.active?
RequestStore.fetch(:current_license) { load_license }
......@@ -83,8 +105,14 @@ class License < ActiveRecord::Base
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
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
def add_on?(code)
......
......@@ -57,7 +57,7 @@ class Namespace < ActiveRecord::Base
'COALESCE(SUM(ps.storage_size), 0) AS storage_size',
'COALESCE(SUM(ps.repository_size), 0) AS repository_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
......
......@@ -1095,7 +1095,7 @@ class Project < ActiveRecord::Base
namespace: namespace.name,
visibility_level: visibility_level,
path_with_namespace: path_with_namespace,
default_branch: default_branch,
default_branch: default_branch
}
# Backward compatibility
......
......@@ -52,7 +52,7 @@ class BambooService < CiService
placeholder: 'Bamboo build plan key like KEY' },
{ type: 'text', name: 'username',
placeholder: 'A user with API access, if applicable' },
{ type: 'password', name: 'password' },
{ type: 'password', name: 'password' }
]
end
......
......@@ -39,7 +39,7 @@ class ChatNotificationService < Service
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'text', name: 'username', placeholder: 'e.g. GitLab' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_default_branch' },
{ type: 'checkbox', name: 'notify_only_default_branch' }
]
end
......
......@@ -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})." },
{ type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs",
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
......@@ -19,7 +19,7 @@ class ExternalWikiService < Service
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
......
......@@ -37,7 +37,7 @@ class FlowdockService < Service
repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
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
......@@ -41,7 +41,7 @@ class HipchatService < Service
placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }
]
end
......
......@@ -58,7 +58,7 @@ class IrkerService < Service
' 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 ' \
' give a channel name.' },
{ type: 'checkbox', name: 'colorize_messages' },
{ type: 'checkbox', name: 'colorize_messages' }
]
end
......
......@@ -90,7 +90,7 @@ class JenkinsDeprecatedService < CiService
get_url = build_page(sha, ref).gsub("#{parsed_url.userinfo}@", "")
auth = {
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)
end
......
......@@ -83,7 +83,7 @@ class JenkinsService < CiService
help: 'The URL-friendly project name. Example: my_project_name'
},
{ type: 'text', name: 'username' },
{ type: 'password', name: 'password' },
{ type: 'password', name: 'password' }
]
end
end
......@@ -149,7 +149,7 @@ class JiraService < IssueTrackerService
data = {
user: {
name: author.name,
url: resource_url(user_path(author)),
url: resource_url(user_path(author))
},
project: {
name: self.project.path_with_namespace,
......
......@@ -73,7 +73,7 @@ class KubernetesService < DeploymentService
{ type: 'textarea',
name: 'ca_pem',
title: 'Custom CA bundle',
placeholder: 'Certificate Authority bundle (PEM format)' },
placeholder: 'Certificate Authority bundle (PEM format)' }
]
end
......
......@@ -35,7 +35,7 @@ class MicrosoftTeamsService < ChatNotificationService
[
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_default_branch' },
{ type: 'checkbox', name: 'notify_only_default_branch' }
]
end
......
......@@ -21,7 +21,7 @@ class MockCiService < CiService
[
{ type: 'text',
name: 'mock_service_url',
placeholder: 'http://localhost:4004' },
placeholder: 'http://localhost:4004' }
]
end
......
......@@ -55,7 +55,7 @@ class PipelinesEmailService < Service
name: 'recipients',
placeholder: 'Emails separated by comma' },
{ type: 'checkbox',
name: 'notify_only_broken_pipelines' },
name: 'notify_only_broken_pipelines' }
]
end
......
......@@ -55,7 +55,7 @@ class PushoverService < Service
['Pushover Echo (long)', 'echo'],
['Up Down (long)', 'updown'],
['None (silent)', 'none']
] },
] }
]
end
......
......@@ -55,7 +55,7 @@ class TeamcityService < CiService
placeholder: 'Build configuration ID' },
{ type: 'text', name: 'username',
placeholder: 'A user with permissions to trigger a manual build' },
{ type: 'password', name: 'password' },
{ type: 'password', name: 'password' }
]
end
......@@ -78,7 +78,7 @@ class TeamcityService < CiService
auth = {
username: username,
password: password,
password: password
}
branch = Gitlab::Git.ref_name(data[:ref])
......
......@@ -859,7 +859,7 @@ class Repository
actual_options = options.merge(
parents: [our_commit, their_commit],
tree: merge_index.write_tree(rugged),
tree: merge_index.write_tree(rugged)
)
commit_id = create_commit(actual_options)
......
......@@ -39,7 +39,7 @@ class SentNotification < ActiveRecord::Base
noteable_type: noteable.class.name,
noteable_id: noteable_id,
commit_id: commit_id,
commit_id: commit_id
)
create(attrs)
......
......@@ -153,18 +153,5 @@ class Snippet < ActiveRecord::Base
where(table[:content].matches(pattern))
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
......@@ -17,7 +17,7 @@ class ProjectSnippetPolicy < BasePolicy
can! :read_project_snippet
end
if @subject.private? && @subject.project.team.member?(@user)
if @subject.project.team.member?(@user)
can! :read_project_snippet
end
end
......
......@@ -31,9 +31,12 @@ class BuildEntity < Grape::Entity
def detailed_status
build.detailed_status(request.current_user)
<<<<<<< HEAD
end
def path_to(route, build)
send("#{route}_path", build.project.namespace, build.project, build)
=======
>>>>>>> origin/master
end
end
......@@ -39,7 +39,7 @@ class EnvironmentEntity < Grape::Entity
end
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(
environment.project.namespace,
environment.project,
......
......@@ -16,7 +16,7 @@ class AkismetService
created_at: DateTime.now,
author: owner.name,
author_email: owner.email,
referrer: options[:referrer],
referrer: options[:referrer]
}
begin
......
......@@ -18,7 +18,7 @@ class AuditEventService
author_name: author_name,
target_id: user_id,
target_type: "User",
target_details: user_name,
target_details: user_name
}
when :create
{
......@@ -27,7 +27,7 @@ class AuditEventService
author_name: author_name,
target_id: user_id,
target_type: "User",
target_details: user_name,
target_details: user_name
}
when :update
{
......@@ -37,7 +37,7 @@ class AuditEventService
author_name: author_name,
target_id: user_id,
target_type: "User",
target_details: user_name,
target_details: user_name
}
end
......@@ -56,7 +56,7 @@ class AuditEventService
author_name: author_name,
target_id: key_title,
target_type: "DeployKey",
target_details: key_title,
target_details: key_title
}
when :create
{
......@@ -64,7 +64,7 @@ class AuditEventService
author_name: author_name,
target_id: key_title,
target_type: "DeployKey",
target_details: key_title,
target_details: key_title
}
end
......@@ -76,7 +76,7 @@ class AuditEventService
with: @details[:with],
target_id: @author.id,
target_type: 'User',
target_details: @author.name,
target_details: @author.name
}
self
......
......@@ -38,7 +38,7 @@ module Boards
attrs.merge!(
add_label_ids: add_label_ids,
remove_label_ids: remove_label_ids,
state_event: issue_state,
state_event: issue_state
)
end
......
......@@ -10,18 +10,6 @@ module Geo
end
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
log('Started repository sync')
started_at, finished_at = fetch_repositories
......@@ -76,7 +64,6 @@ module Geo
def try_obtain_lease
log('Trying to obtain lease to sync repository')
repository_lease = Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT).try_obtain
if repository_lease.nil?
......@@ -93,25 +80,7 @@ module Geo
Gitlab::ExclusiveLease.cancel(lease_key, repository_lease)
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)
return if synced_registry_exists?
log('Updating registry information')
registry = Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id)
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
class ScheduleRepoFetchService
def initialize(params)
@project_id = params[:project_id]
@remote_url = params[:remote_url]
@remote_url = params[:project][:git_ssh_url]
end
def execute
......
......@@ -321,7 +321,7 @@ class NotificationService
recipients ||= NotificationRecipientService.new(pipeline.project).build_pipeline_recipients(
pipeline,
pipeline.user,
action: pipeline.status,
action: pipeline.status
).map(&:notification_email)
if recipients.any?
......
......@@ -27,7 +27,7 @@ module Projects
{
domain: domain.domain,
certificate: domain.certificate,
key: domain.key,
key: domain.key
}
end
end
......
module Search
class SnippetService
include Gitlab::CurrentSettings
attr_accessor :current_user, :params
def initialize(user, params)
......@@ -8,13 +7,9 @@ module Search
end
def execute
if current_application_settings.elasticsearch_search?
Gitlab::Elastic::SnippetSearchResults.new(current_user,
params[:search])
else
snippets = Snippet.accessible_to(current_user)
Gitlab::SnippetSearchResults.new(snippets, params[:search])
end
snippets = SnippetsFinder.new(current_user).execute
Gitlab::SnippetSearchResults.new(snippets, params[:search])
end
def scope
......
......@@ -51,7 +51,7 @@ class SystemHooksService
path: model.path,
group_id: model.id,
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
data.merge!(group_member_data(model))
......@@ -113,7 +113,7 @@ class SystemHooksService
user_name: model.user.name,
user_email: model.user.email,
user_id: model.user.id,
group_access: model.human_access,
group_access: model.human_access
}
end
end
......@@ -18,19 +18,26 @@
or adding ssh key. But you can also enable extra triggers like Push events.
.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'
.prepend-left-20
= form.label :push_events, class: 'list-label' do
%strong Push events
%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
= form.check_box :tag_push_events, class: 'pull-left'
.prepend-left-20
= form.label :tag_push_events, class: 'list-label' do
%strong Tag push events
%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.label :enable_ssl_verification, 'SSL verification', class: 'control-label checkbox'
.col-sm-10
......
......@@ -27,7 +27,7 @@
= link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
.monospace= hook.url
%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)
%span.label.label-gray= trigger.titleize
%span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
......@@ -10,4 +10,4 @@
- else
:plain
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 @@
.help-block.text-danger.js-branch-name-error
.form-group
= label_tag :ref, 'Create from', class: 'control-label'
.col-sm-10.dropdown.create-from
= hidden_field_tag :ref, default_ref
= 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
.text-left.dropdown-toggle-text= default_ref
= render 'shared/ref_dropdown', dropdown_class: 'wide'
.col-sm-10.create-from
.dropdown
= hidden_field_tag :ref, 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
.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
.form-actions
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
......
......@@ -10,7 +10,7 @@
.panel-body
%pre
: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|
= render "shared/import_form", f: f
......
......@@ -22,7 +22,7 @@
.panel-body
%pre
:preserve
#{@project.import_error.try(:strip)}
#{h(@project.import_error.try(:strip))}
.form-group
= f.check_box :mirror, class: "pull-left"
.prepend-left-20
......@@ -66,7 +66,7 @@
.panel-body
%pre
:preserve
#{@remote_mirror.last_error.strip}
#{h(@remote_mirror.last_error.strip)}
= f.fields_for :remote_mirrors, @remote_mirror do |rm_form|
.form-group
= rm_form.check_box :enabled, class: "pull-left"
......
......@@ -28,7 +28,7 @@
%h3 Clone your wiki
%pre.dark
: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}
%h3 Start Gollum and edit locally
......
......@@ -29,6 +29,8 @@
- if note.system
%span.system-note-message
= note.redacted_note_html
.original-note-content.hidden
= note.note
%a{ href: "##{dom_id(note)}" }
= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago')
- unless note.system?
......
......@@ -2,15 +2,18 @@ class GeoBackfillWorker
include Sidekiq::Worker
include CronjobQueue
RUN_TIME = 5.minutes.to_i.freeze
BATCH_SIZE = 100.freeze
RUN_TIME = 5.minutes.to_i
BATCH_SIZE = 100
LAST_SYNC_INTERVAL = 24.hours
def perform
return unless Gitlab::Geo.configured?
return unless Gitlab::Geo.primary_node.present?
start_time = Time.now
project_ids = find_project_ids
start_time = Time.now
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)"
......@@ -38,12 +41,34 @@ class GeoBackfillWorker
private
def find_project_ids
def find_project_ids_not_synced
Project.where.not(id: Geo::ProjectRegistry.synced.pluck(:project_id))
.limit(BATCH_SIZE)
.pluck(:id)
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)
Time.now - start_time >= RUN_TIME
end
......
......@@ -8,14 +8,6 @@ class GeoRepositoryFetchWorker
def perform(project_id, clone_url)
project = Project.find(project_id)
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}"
Geo::RepositoryUpdateService.new(project, clone_url, logger).execute
end
end
......@@ -23,26 +23,33 @@ class PostReceive
# Triggers repository update on secondary nodes when Geo is enabled
Gitlab::Geo.notify_wiki_update(post_received.project) if Gitlab::Geo.enabled?
else
# TODO: gitlab-org/gitlab-ce#26325. Remove this.
if Gitlab::Geo.enabled?
hook_data = {
event_name: 'repository_update',
project_id: post_received.project.id,
project: post_received.project.hook_attrs,
remote_url: post_received.project.ssh_url_to_repo
}
SystemHooksService.new.execute_hooks(hook_data, :repository_update_hooks)
process_project_changes(post_received)
process_repository_update(post_received)
end
end
def process_repository_update(post_received)
changes = []
refs = Set.new
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
process_project_changes(post_received)
changes << Gitlab::DataBuilder::Repository.single_change(oldrev, newrev, ref)
refs << ref
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
def process_project_changes(post_received)
post_received.changes.each do |change|
oldrev, newrev, ref = change.strip.split(' ')
post_received.changes_refs do |oldrev, newrev, ref|
@user ||= post_received.identify(newrev)
unless @user
......
......@@ -8,7 +8,7 @@ module RepositoryCheck
Project.select(:id).find_in_batches(batch_size: 100) do |batch|
Project.where(id: batch.map(&:id)).update_all(
last_repository_check_failed: nil,
last_repository_check_at: nil,
last_repository_check_at: nil
)
end
end
......
......@@ -7,7 +7,7 @@ module RepositoryCheck
project = Project.find(project_id)
project.update_columns(
last_repository_check_failed: !check(project),
last_repository_check_at: Time.now,
last_repository_check_at: Time.now
)
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