Commit d5e5eb1d authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-01-03

# Conflicts:
#	app/assets/javascripts/init_legacy_filters.js
#	app/assets/javascripts/milestone_select.js
#	app/models/project_team.rb
#	doc/user/project/quick_actions.md
#	features/steps/shared/project.rb
#	qa/qa/page/menu/admin.rb
#	spec/controllers/projects/imports_controller_spec.rb
#	spec/features/issues/form_spec.rb
#	spec/features/merge_requests/edit_mr_spec.rb
#	spec/lib/gitlab/reference_extractor_spec.rb
#	spec/requests/api/issues_spec.rb
#	spec/services/git_push_service_spec.rb
#	spec/services/quick_actions/interpret_service_spec.rb

[ci skip]
parents a92be4e3 5e310367
...@@ -625,6 +625,14 @@ codequality: ...@@ -625,6 +625,14 @@ codequality:
artifacts: artifacts:
paths: [codeclimate.json] paths: [codeclimate.json]
sast:
image: registry.gitlab.com/gitlab-org/gl-sast:latest
before_script: []
script:
- /app/bin/run .
artifacts:
paths: [gl-sast-report.json]
qa:internal: qa:internal:
<<: *dedicated-runner <<: *dedicated-runner
<<: *except-docs <<: *except-docs
......
...@@ -12,7 +12,7 @@ gem 'sprockets', '~> 3.7.0' ...@@ -12,7 +12,7 @@ gem 'sprockets', '~> 3.7.0'
gem 'default_value_for', '~> 3.0.0' gem 'default_value_for', '~> 3.0.0'
# Supported DBs # Supported DBs
gem 'mysql2', '~> 0.4.5', group: :mysql gem 'mysql2', '~> 0.4.10', group: :mysql
gem 'pg', '~> 0.18.2', group: :postgres gem 'pg', '~> 0.18.2', group: :postgres
gem 'rugged', '~> 0.26.0' gem 'rugged', '~> 0.26.0'
...@@ -295,7 +295,7 @@ group :metrics do ...@@ -295,7 +295,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false gem 'influxdb', '~> 0.2', require: false
# Prometheus # Prometheus
gem 'prometheus-client-mmap', '~> 0.7.0.beta43' gem 'prometheus-client-mmap', '~> 0.7.0.beta44'
gem 'raindrops', '~> 0.18' gem 'raindrops', '~> 0.18'
end end
...@@ -418,7 +418,7 @@ group :ed25519 do ...@@ -418,7 +418,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.61.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.62.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false gem 'toml-rb', '~> 0.3.15', require: false
......
...@@ -308,7 +308,7 @@ GEM ...@@ -308,7 +308,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly-proto (0.61.0) gitaly-proto (0.62.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (4.7.6) github-linguist (4.7.6)
...@@ -533,7 +533,7 @@ GEM ...@@ -533,7 +533,7 @@ GEM
mustermann (1.0.0) mustermann (1.0.0)
mustermann-grape (1.0.0) mustermann-grape (1.0.0)
mustermann (~> 1.0.0) mustermann (~> 1.0.0)
mysql2 (0.4.5) mysql2 (0.4.10)
net-ldap (0.16.0) net-ldap (0.16.0)
net-ntp (2.1.3) net-ntp (2.1.3)
net-ssh (4.1.0) net-ssh (4.1.0)
...@@ -663,7 +663,7 @@ GEM ...@@ -663,7 +663,7 @@ GEM
parser parser
unparser unparser
procto (0.0.3) procto (0.0.3)
prometheus-client-mmap (0.7.0.beta43) prometheus-client-mmap (0.7.0.beta44)
pry (0.10.4) pry (0.10.4)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
...@@ -737,7 +737,7 @@ GEM ...@@ -737,7 +737,7 @@ GEM
json json
recursive-open-struct (1.0.0) recursive-open-struct (1.0.0)
redcarpet (3.4.0) redcarpet (3.4.0)
redis (3.3.3) redis (3.3.5)
redis-actionpack (5.0.2) redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6) actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3) redis-rack (>= 1, < 3)
...@@ -868,11 +868,11 @@ GEM ...@@ -868,11 +868,11 @@ GEM
rack rack
shoulda-matchers (3.1.2) shoulda-matchers (3.1.2)
activesupport (>= 4.0.0) activesupport (>= 4.0.0)
sidekiq (5.0.4) sidekiq (5.0.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0) connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0) rack-protection (>= 1.5.0)
redis (~> 3.3, >= 3.3.3) redis (>= 3.3.4, < 5)
sidekiq-cron (0.6.0) sidekiq-cron (0.6.0)
rufus-scheduler (>= 3.3.0) rufus-scheduler (>= 3.3.0)
sidekiq (>= 4.2.1) sidekiq (>= 4.2.1)
...@@ -1081,7 +1081,7 @@ DEPENDENCIES ...@@ -1081,7 +1081,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.61.0) gitaly-proto (~> 0.62.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
...@@ -1124,7 +1124,7 @@ DEPENDENCIES ...@@ -1124,7 +1124,7 @@ DEPENDENCIES
method_source (~> 0.8) method_source (~> 0.8)
minitest (~> 5.7.0) minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6) mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.4.5) mysql2 (~> 0.4.10)
net-ldap net-ldap
net-ntp net-ntp
net-ssh (~> 4.1.0) net-ssh (~> 4.1.0)
...@@ -1160,7 +1160,7 @@ DEPENDENCIES ...@@ -1160,7 +1160,7 @@ DEPENDENCIES
peek-sidekiq (~> 1.0.3) peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2) pg (~> 0.18.2)
premailer-rails (~> 1.9.7) premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.7.0.beta43) prometheus-client-mmap (~> 0.7.0.beta44)
pry-byebug (~> 3.4.1) pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4) pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1) rack-attack (~> 4.4.1)
......
...@@ -111,7 +111,6 @@ $(() => { ...@@ -111,7 +111,6 @@ $(() => {
if (list.type === 'closed') { if (list.type === 'closed') {
list.position = Infinity; list.position = Infinity;
list.label = { description: 'Shows all closed issues. Moving an issue to this list closes it' };
} else if (list.type === 'backlog') { } else if (list.type === 'backlog') {
list.position = -1; list.position = -1;
} }
......
...@@ -140,7 +140,7 @@ class FilteredSearchManager { ...@@ -140,7 +140,7 @@ class FilteredSearchManager {
this.handleInputVisualTokenWrapper = this.handleInputVisualToken.bind(this); this.handleInputVisualTokenWrapper = this.handleInputVisualToken.bind(this);
this.checkForEnterWrapper = this.checkForEnter.bind(this); this.checkForEnterWrapper = this.checkForEnter.bind(this);
this.onClearSearchWrapper = this.onClearSearch.bind(this); this.onClearSearchWrapper = this.onClearSearch.bind(this);
this.checkForBackspaceWrapper = this.checkForBackspace.bind(this); this.checkForBackspaceWrapper = this.checkForBackspace.call(this);
this.removeSelectedTokenKeydownWrapper = this.removeSelectedTokenKeydown.bind(this); this.removeSelectedTokenKeydownWrapper = this.removeSelectedTokenKeydown.bind(this);
this.unselectEditTokensWrapper = this.unselectEditTokens.bind(this); this.unselectEditTokensWrapper = this.unselectEditTokens.bind(this);
this.editTokenWrapper = this.editToken.bind(this); this.editTokenWrapper = this.editToken.bind(this);
...@@ -193,22 +193,34 @@ class FilteredSearchManager { ...@@ -193,22 +193,34 @@ class FilteredSearchManager {
this.unbindStateEvents(); this.unbindStateEvents();
} }
checkForBackspace(e) { checkForBackspace() {
let backspaceCount = 0;
// closure for keeping track of the number of backspace keystrokes
return (e) => {
// 8 = Backspace Key // 8 = Backspace Key
// 46 = Delete Key // 46 = Delete Key
if (e.keyCode === 8 || e.keyCode === 46) { if (e.keyCode === 8 || e.keyCode === 46) {
const { lastVisualToken } = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); const { lastVisualToken } = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
const { tokenName, tokenValue } = gl.DropdownUtils.getVisualTokenValues(lastVisualToken); const { tokenName, tokenValue } = gl.DropdownUtils.getVisualTokenValues(lastVisualToken);
const canEdit = tokenName && this.canEdit && this.canEdit(tokenName, tokenValue); const canEdit = tokenName && this.canEdit && this.canEdit(tokenName, tokenValue);
if (this.filteredSearchInput.value === '' && lastVisualToken && canEdit) { if (this.filteredSearchInput.value === '' && lastVisualToken && canEdit) {
backspaceCount += 1;
if (backspaceCount === 2) {
backspaceCount = 0;
this.filteredSearchInput.value = gl.FilteredSearchVisualTokens.getLastTokenPartial(); this.filteredSearchInput.value = gl.FilteredSearchVisualTokens.getLastTokenPartial();
gl.FilteredSearchVisualTokens.removeLastTokenPartial(); gl.FilteredSearchVisualTokens.removeLastTokenPartial();
} }
}
// Reposition dropdown so that it is aligned with cursor // Reposition dropdown so that it is aligned with cursor
this.dropdownManager.updateCurrentDropdownOffset(); this.dropdownManager.updateCurrentDropdownOffset();
} else {
backspaceCount = 0;
} }
};
} }
checkForEnter(e) { checkForEnter(e) {
......
...@@ -4,8 +4,11 @@ import subscriptionSelect from './subscription_select'; ...@@ -4,8 +4,11 @@ import subscriptionSelect from './subscription_select';
import UsersSelect from './users_select'; import UsersSelect from './users_select';
import issueStatusSelect from './issue_status_select'; import issueStatusSelect from './issue_status_select';
import MilestoneSelect from './milestone_select'; import MilestoneSelect from './milestone_select';
<<<<<<< HEAD
import WeightSelect from 'ee/weight_select'; // eslint-disable-line import/first import WeightSelect from 'ee/weight_select'; // eslint-disable-line import/first
=======
>>>>>>> upstream/master
export default () => { export default () => {
new UsersSelect(); new UsersSelect();
......
import _ from 'underscore'; import _ from 'underscore';
import { visitUrl } from './lib/utils/url_utility'; import { visitUrl } from './lib/utils/url_utility';
import bp from './breakpoints'; import bp from './breakpoints';
import { bytesToKiB } from './lib/utils/number_utils'; import { numberToHumanSize } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils'; import { setCiStatusFavicon } from './lib/utils/common_utils';
import { timeFor } from './lib/utils/datetime_utility'; import { timeFor } from './lib/utils/datetime_utility';
...@@ -193,7 +193,7 @@ export default class Job { ...@@ -193,7 +193,7 @@ export default class Job {
// we need to show a message warning the user about that. // we need to show a message warning the user about that.
if (this.logBytes < log.total) { if (this.logBytes < log.total) {
// size is in bytes, we need to calculate KiB // size is in bytes, we need to calculate KiB
const size = bytesToKiB(this.logBytes); const size = numberToHumanSize(this.logBytes);
$('.js-truncated-info-size').html(`${size}`); $('.js-truncated-info-size').html(`${size}`);
this.$truncatedInfo.removeClass('hidden'); this.$truncatedInfo.removeClass('hidden');
} else { } else {
......
...@@ -226,5 +226,8 @@ export default class MilestoneSelect { ...@@ -226,5 +226,8 @@ export default class MilestoneSelect {
}); });
} }
} }
<<<<<<< HEAD
window.MilestoneSelect = MilestoneSelect; window.MilestoneSelect = MilestoneSelect;
=======
>>>>>>> upstream/master
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
color: $gl-text-color; color: $gl-text-color;
font-weight: $gl-font-weight-normal; font-weight: $gl-font-weight-normal;
font-size: 14px; font-size: 14px;
line-height: 36px;
&.diff-collapsed { &.diff-collapsed {
padding: 5px; padding: 5px;
......
...@@ -358,10 +358,6 @@ ...@@ -358,10 +358,6 @@
} }
.sidebar-top-level-items > li { .sidebar-top-level-items > li {
&.active a {
padding-left: 12px;
}
.sidebar-sub-level-items { .sidebar-sub-level-items {
&:not(.flyout-list) { &:not(.flyout-list) {
display: none; display: none;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
padding: 10px 15px; padding: 10px 15px;
min-height: 20px; min-height: 20px;
border-bottom: 1px solid $list-border; border-bottom: 1px solid $list-border;
word-wrap: break-word;
&::after { &::after {
content: " "; content: " ";
......
...@@ -159,7 +159,6 @@ ...@@ -159,7 +159,6 @@
} }
} }
/* /*
* Last push widget * Last push widget
*/ */
...@@ -182,6 +181,12 @@ ...@@ -182,6 +181,12 @@
.event-item { .event-item {
padding-left: 0; padding-left: 0;
&.event-inline {
.event-title {
line-height: 20px;
}
}
.event-title { .event-title {
white-space: normal; white-space: normal;
overflow: visible; overflow: visible;
......
class PasswordsController < Devise::PasswordsController class PasswordsController < Devise::PasswordsController
include Gitlab::CurrentSettings include Gitlab::CurrentSettings
skip_before_action :require_no_authentication, only: [:edit, :update]
before_action :resource_from_email, only: [:create] before_action :resource_from_email, only: [:create]
before_action :check_password_authentication_available, only: [:create] before_action :check_password_authentication_available, only: [:create]
before_action :throttle_reset, only: [:create] before_action :throttle_reset, only: [:create]
......
...@@ -46,14 +46,16 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -46,14 +46,16 @@ class Projects::BranchesController < Projects::ApplicationController
result = CreateBranchService.new(project, current_user) result = CreateBranchService.new(project, current_user)
.execute(branch_name, ref) .execute(branch_name, ref)
if params[:issue_iid] success = (result[:status] == :success)
if params[:issue_iid] && success
issue = IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:issue_iid]) issue = IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:issue_iid])
SystemNoteService.new_issue_branch(issue, @project, current_user, branch_name) if issue SystemNoteService.new_issue_branch(issue, @project, current_user, branch_name) if issue
end end
respond_to do |format| respond_to do |format|
format.html do format.html do
if result[:status] == :success if success
if redirect_to_autodeploy if redirect_to_autodeploy
redirect_to url_to_autodeploy_setup(project, branch_name), redirect_to url_to_autodeploy_setup(project, branch_name),
notice: view_context.autodeploy_flash_notice(branch_name) notice: view_context.autodeploy_flash_notice(branch_name)
...@@ -67,7 +69,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -67,7 +69,7 @@ class Projects::BranchesController < Projects::ApplicationController
end end
format.json do format.json do
if result[:status] == :success if success
render json: { name: branch_name, url: project_tree_url(@project, branch_name) } render json: { name: branch_name, url: project_tree_url(@project, branch_name) }
else else
render json: result[:messsage], status: :unprocessable_entity render json: result[:messsage], status: :unprocessable_entity
......
...@@ -29,17 +29,17 @@ class Projects::RunnersController < Projects::ApplicationController ...@@ -29,17 +29,17 @@ class Projects::RunnersController < Projects::ApplicationController
def resume def resume
if Ci::UpdateRunnerService.new(@runner).update(active: true) if Ci::UpdateRunnerService.new(@runner).update(active: true)
redirect_to runner_path(@runner), notice: 'Runner was successfully updated.' redirect_to runners_path(@project), notice: 'Runner was successfully updated.'
else else
redirect_to runner_path(@runner), alert: 'Runner was not updated.' redirect_to runners_path(@project), alert: 'Runner was not updated.'
end end
end end
def pause def pause
if Ci::UpdateRunnerService.new(@runner).update(active: false) if Ci::UpdateRunnerService.new(@runner).update(active: false)
redirect_to runner_path(@runner), notice: 'Runner was successfully updated.' redirect_to runners_path(@project), notice: 'Runner was successfully updated.'
else else
redirect_to runner_path(@runner), alert: 'Runner was not updated.' redirect_to runners_path(@project), alert: 'Runner was not updated.'
end end
end end
......
...@@ -23,8 +23,13 @@ class DiffDiscussion < Discussion ...@@ -23,8 +23,13 @@ class DiffDiscussion < Discussion
def merge_request_version_params def merge_request_version_params
return unless for_merge_request? return unless for_merge_request?
version_params = get_params
return version_params unless on_merge_request_commit? && commit_id
version_params ||= {}
version_params.tap do |params| version_params.tap do |params|
params[:commit_id] = commit_id if on_merge_request_commit? params[:commit_id] = commit_id
end end
end end
...@@ -37,7 +42,7 @@ class DiffDiscussion < Discussion ...@@ -37,7 +42,7 @@ class DiffDiscussion < Discussion
private private
def version_params def get_params
return {} if active? return {} if active?
noteable.version_params_for(position.diff_refs) noteable.version_params_for(position.diff_refs)
......
...@@ -24,7 +24,11 @@ class ProjectTeam ...@@ -24,7 +24,11 @@ class ProjectTeam
end end
def add_role(user, role, current_user: nil) def add_role(user, role, current_user: nil)
<<<<<<< HEAD
public_send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend public_send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend
=======
send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend
>>>>>>> upstream/master
end end
def find_member(user_id) def find_member(user_id)
......
...@@ -1059,10 +1059,6 @@ class Repository ...@@ -1059,10 +1059,6 @@ class Repository
raw_repository.fetch_source_branch!(source_repository.raw_repository, source_branch, local_ref) raw_repository.fetch_source_branch!(source_repository.raw_repository, source_branch, local_ref)
end end
def remote_exists?(name)
raw_repository.remote_exists?(name)
end
def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:) def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:)
raw_repository.compare_source_branch(target_branch_name, source_repository.raw_repository, source_branch_name, straight: straight) raw_repository.compare_source_branch(target_branch_name, source_repository.raw_repository, source_branch_name, straight: straight)
end end
......
...@@ -96,8 +96,8 @@ class User < ActiveRecord::Base ...@@ -96,8 +96,8 @@ class User < ActiveRecord::Base
has_one :user_synced_attributes_metadata, autosave: true has_one :user_synced_attributes_metadata, autosave: true
# Groups # Groups
has_many :members, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :members
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, source: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent has_many :group_members, -> { where(requested_at: nil) }, source: 'GroupMember'
has_many :groups, through: :group_members has_many :groups, through: :group_members
has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group
has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group
...@@ -105,7 +105,7 @@ class User < ActiveRecord::Base ...@@ -105,7 +105,7 @@ class User < ActiveRecord::Base
# Projects # Projects
has_many :groups_projects, through: :groups, source: :projects has_many :groups_projects, through: :groups, source: :projects
has_many :personal_projects, through: :namespace, source: :projects has_many :personal_projects, through: :namespace, source: :projects
has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :project_members, -> { where(requested_at: nil) }
has_many :projects, through: :project_members has_many :projects, through: :project_members
has_many :created_projects, foreign_key: :creator_id, class_name: 'Project' has_many :created_projects, foreign_key: :creator_id, class_name: 'Project'
has_many :users_star_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :users_star_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
......
...@@ -23,7 +23,7 @@ module MergeRequests ...@@ -23,7 +23,7 @@ module MergeRequests
# when there are no conflict files. # when there are no conflict files.
conflicts.files.each(&:lines) conflicts.files.each(&:lines)
@conflicts_can_be_resolved_in_ui = conflicts.files.length > 0 @conflicts_can_be_resolved_in_ui = conflicts.files.length > 0
rescue Rugged::OdbError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing rescue Gitlab::Git::CommandError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing
@conflicts_can_be_resolved_in_ui = false @conflicts_can_be_resolved_in_ui = false
end end
end end
......
...@@ -26,7 +26,7 @@ module Projects ...@@ -26,7 +26,7 @@ module Projects
name: @project.name, name: @project.name,
path: @project.path, path: @project.path,
shared_runners_enabled: @project.shared_runners_enabled, shared_runners_enabled: @project.shared_runners_enabled,
namespace_id: @params[:namespace].try(:id) || current_user.namespace.id namespace_id: target_namespace.id
} }
if @project.avatar.present? && @project.avatar.image? if @project.avatar.present? && @project.avatar.image?
...@@ -74,14 +74,14 @@ module Projects ...@@ -74,14 +74,14 @@ module Projects
Projects::ForksCountService.new(@project).refresh_cache Projects::ForksCountService.new(@project).refresh_cache
end end
def target_namespace
@target_namespace ||= @params[:namespace] || current_user.namespace
end
def allowed_visibility_level def allowed_visibility_level
project_level = @project.visibility_level target_level = [@project.visibility_level, target_namespace.visibility_level].min
if Gitlab::VisibilityLevel.non_restricted_level?(project_level) Gitlab::VisibilityLevel.closest_allowed_level(target_level)
project_level
else
Gitlab::VisibilityLevel.highest_allowed_level
end
end end
end end
end end
...@@ -31,6 +31,11 @@ module Users ...@@ -31,6 +31,11 @@ module Users
return user return user
end end
# Calling all before/after_destroy hooks for the user because
# there is no dependent: destroy in the relationship. And the removal
# is done by a foreign_key. Otherwise they won't be called
user.members.find_each { |member| member.run_callbacks(:destroy) }
user.solo_owned_groups.each do |group| user.solo_owned_groups.each do |group|
Groups::DestroyService.new(group, current_user).execute Groups::DestroyService.new(group, current_user).execute
end end
......
- add_to_breadcrumbs "Applications", oauth_applications_path
- breadcrumb_title @application.name
- page_title @application.name, "Applications" - page_title @application.name, "Applications"
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
......
...@@ -131,7 +131,7 @@ ...@@ -131,7 +131,7 @@
%span.badge.count= number_with_delimiter(AbuseReport.count(:all)) %span.badge.count= number_with_delimiter(AbuseReport.count(:all))
%ul.sidebar-sub-level-items.is-fly-out-only %ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :abuse_reports, html_options: { class: "fly-out-top-item" } ) do = nav_link(controller: :abuse_reports, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_broadcast_messages_path do = link_to admin_abuse_reports_path do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
#{ _('Abuse Reports') } #{ _('Abuse Reports') }
%span.badge.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(AbuseReport.count(:all)) %span.badge.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(AbuseReport.count(:all))
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
.row.prepend-top-default .row.prepend-top-default
.col-lg-4.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
%h3.prepend-top-0 %h4.prepend-top-0
= page_title = page_title
%p %p
This is a security log of important events involving your account. This is a security log of important events involving your account.
......
- page_title "GPG Keys" - page_title "GPG Keys"
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head' = render 'profiles/head'
.row.prepend-top-default .row.prepend-top-default
......
- add_to_breadcrumbs "SSH Keys", profile_keys_path
- breadcrumb_title @key.title
- page_title @key.title, "SSH Keys" - page_title @key.title, "SSH Keys"
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head' = render 'profiles/head'
......
...@@ -10,16 +10,16 @@ ...@@ -10,16 +10,16 @@
%li= msg %li= msg
= hidden_field_tag :notification_type, 'global' = hidden_field_tag :notification_type, 'global'
.row .row.prepend-top-default
.col-lg-4.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
%h4 %h4.prepend-top-0
= page_title = page_title
%p %p
You can specify notification level per group or per project. You can specify notification level per group or per project.
%p %p
By default, all projects and groups will use the global notifications setting. By default, all projects and groups will use the global notifications setting.
.col-lg-8 .col-lg-8
%h5 %h5.prepend-top-0
Global notification settings Global notification settings
= form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f| = form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f|
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
.js-truncated-info.truncated-info.hidden-xs.pull-left.hidden< .js-truncated-info.truncated-info.hidden-xs.pull-left.hidden<
Showing last Showing last
%span.js-truncated-info-size.truncated-info-size>< %span.js-truncated-info-size.truncated-info-size><
KiB of log - of log -
%a.js-raw-link.raw-link{ href: raw_project_job_path(@project, @build) }>< Complete Raw %a.js-raw-link.raw-link{ href: raw_project_job_path(@project, @build) }>< Complete Raw
.controllers.pull-right .controllers.pull-right
......
...@@ -4,14 +4,17 @@ ...@@ -4,14 +4,17 @@
= render 'projects/merge_requests/diffs/commit_widget' = render 'projects/merge_requests/diffs/commit_widget'
- if @merge_request_diff&.empty? - if @merge_request_diff&.empty?
.nothing-here-block .row.empty-state.nothing-here-block
= image_tag 'illustrations/merge_request_changes_empty.svg' .col-xs-12
= succeed '.' do .svg-content= image_tag 'illustrations/merge_request_changes_empty.svg'
.col-xs-12
.text-content.text-center
%p
No changes between No changes between
%span.ref-name= @merge_request.source_branch %span.ref-name= @merge_request.source_branch
and and
%span.ref-name= @merge_request.target_branch %span.ref-name= @merge_request.target_branch
%p= link_to 'Create commit', project_new_blob_path(@project, @merge_request.source_branch), class: 'btn btn-save' .text-center= link_to 'Create commit', project_new_blob_path(@project, @merge_request.source_branch), class: 'btn btn-save'
- else - else
- diff_viewable = @merge_request_diff ? @merge_request_diff.collected? || @merge_request_diff.overflow? : true - diff_viewable = @merge_request_diff ? @merge_request_diff.collected? || @merge_request_diff.overflow? : true
- if diff_viewable - if diff_viewable
......
...@@ -17,6 +17,10 @@ ...@@ -17,6 +17,10 @@
.pull-right .pull-right
- if @project_runners.include?(runner) - if @project_runners.include?(runner)
- if runner.active?
= link_to 'Pause', pause_project_runner_path(@project, runner), method: :post, class: 'btn btn-sm btn-danger', data: { confirm: "Are you sure?" }
- else
= link_to 'Resume', resume_project_runner_path(@project, runner), method: :post, class: 'btn btn-success btn-sm'
- if runner.belongs_to_one_project? - if runner.belongs_to_one_project?
= link_to 'Remove Runner', runner_path(runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm' = link_to 'Remove Runner', runner_path(runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
- else - else
......
- resource_name = spammable.class.model_name.singular - resource_name = spammable.class.model_name.singular
- humanized_resource_name = spammable.class.model_name.human.downcase - humanized_resource_name = spammable.class.model_name.human.downcase
- script = local_assigns.fetch(:script, true) - script = local_assigns.fetch(:script, true)
- method = params[:action] == 'create' ? :post : :put
- has_submit = local_assigns.fetch(:has_submit, true) - has_submit = local_assigns.fetch(:has_submit, true)
= form_for resource_name, method: :post, html: { class: 'recaptcha-form js-recaptcha-form' } do |f| = form_for resource_name, method: method, html: { class: 'recaptcha-form js-recaptcha-form' } do |f|
.recaptcha .recaptcha
- params[resource_name].each do |field, value| - params[resource_name].each do |field, value|
= hidden_field(resource_name, field, value: value) = hidden_field(resource_name, field, value: value)
......
---
title: "Ignore lost+found folder during backup on a volume"
merge_request: 16036
author: Julien Millau
type: fixed
\ No newline at end of file
---
title: Improve search query for issues.
merge_request:
author:
type: performance
---
title: Add pause/resume button to project runners
merge_request: 16032
author: Mario de la Ossa
type: added
---
title: Fix when branch creation fails don't post system note
merge_request:
author: Mateusz Bajorski
type: fixed
---
title: Support new chat notifications parameters in Services API
merge_request: 11435
author:
type: added
---
title: Clears visual token on second backspace
merge_request:
author: Martin Wortschack
type: fixed
---
title: Fix breadcrumbs in User Settings
merge_request: 16172
author: rfwatson
type: fixed
---
title: Bump mysql2 gem version from 0.4.5 to 0.4.10
merge_request:
author: asaparov
type: other
---
title: Don't link LFS objects to a project when unlinking forks when they were already
linked
merge_request: 16006
author:
type: fixed
---
title: Allow forking a public project to a private group
merge_request: 16050
author:
type: changed
---
title: Fix abuse reports link url in admin area navbar
merge_request: 16068
author: megos
type: fixed
---
title: Fix activity inline event line height on mobile
merge_request: 16121
author: George Tsiolis
type: fixed
---
title: Adjust content width for User Settings, GPG Keys
merge_request: 16093
author: George Tsiolis
type: fixed
---
title: Keep typographic hierarchy in User Settings
merge_request: 16090
author: George Tsiolis
type: fixed
---
title: Remove unnecessary sidebar element realignment
merge_request: 16159
author: George Tsiolis
type: fixed
---
title: Fixing error 500 when member exist but not the user
merge_request: 15970
author:
type: fixed
---
title: Reduce the number of buckets in gitlab_cache_operation_duration_seconds metric
merge_request: 15881
author:
type: changed
--- ---
title: Execute project hooks and services after commit when moving an issue title: Gracefully handle garbled URIs in Markdown
merge_request: merge_request:
author: author:
type: fixed type: fixed
---
title: Humanize the units of "Showing last X KiB of log" in job trace
merge_request:
author:
type: fixed
---
title: show None when issue is in closed list and no labels assigned
merge_request: 15976
author: Christiaan Van den Poel
type: fixed
...@@ -17,6 +17,11 @@ end ...@@ -17,6 +17,11 @@ end
require ::File.expand_path('../config/environment', __FILE__) require ::File.expand_path('../config/environment', __FILE__)
warmup do |app|
client = Rack::MockRequest.new(app)
client.get('/')
end
map ENV['RAILS_RELATIVE_URL_ROOT'] || "/" do map ENV['RAILS_RELATIVE_URL_ROOT'] || "/" do
run Gitlab::Application run Gitlab::Application
end end
...@@ -79,3 +79,8 @@ elsif Gitlab::Database.mysql? ...@@ -79,3 +79,8 @@ elsif Gitlab::Database.mysql?
NATIVE_DATABASE_TYPES[:datetime_with_timezone] = { name: 'timestamp' } NATIVE_DATABASE_TYPES[:datetime_with_timezone] = { name: 'timestamp' }
end end
end end
# Ensure `datetime_with_timezone` columns are correctly written to schema.rb
if (ActiveRecord::Base.connection.active? rescue false)
ActiveRecord::Base.connection.send :reload_type_map
end
...@@ -14,8 +14,8 @@ AssetSync.configure do |config| ...@@ -14,8 +14,8 @@ AssetSync.configure do |config|
config.fog_directory = ENV['FOG_DIRECTORY'] if ENV.has_key?('FOG_DIRECTORY') config.fog_directory = ENV['FOG_DIRECTORY'] if ENV.has_key?('FOG_DIRECTORY')
config.fog_region = ENV['FOG_REGION'] if ENV.has_key?('FOG_REGION') config.fog_region = ENV['FOG_REGION'] if ENV.has_key?('FOG_REGION')
config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] if ENV.has_key?('AWS_ACCESS_KEY_ID') config.aws_access_key_id = ENV['ASSETS_AWS_ACCESS_KEY_ID'] if ENV.has_key?('ASSETS_AWS_ACCESS_KEY_ID')
config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] if ENV.has_key?('AWS_SECRET_ACCESS_KEY') config.aws_secret_access_key = ENV['ASSETS_AWS_SECRET_ACCESS_KEY'] if ENV.has_key?('ASSETS_AWS_SECRET_ACCESS_KEY')
config.aws_reduced_redundancy = ENV['AWS_REDUCED_REDUNDANCY'] == true if ENV.has_key?('AWS_REDUCED_REDUNDANCY') config.aws_reduced_redundancy = ENV['AWS_REDUCED_REDUNDANCY'] == true if ENV.has_key?('AWS_REDUCED_REDUNDANCY')
config.rackspace_username = ENV['RACKSPACE_USERNAME'] if ENV.has_key?('RACKSPACE_USERNAME') config.rackspace_username = ENV['RACKSPACE_USERNAME'] if ENV.has_key?('RACKSPACE_USERNAME')
......
...@@ -423,8 +423,8 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -423,8 +423,8 @@ constraints(ProjectUrlConstrainer.new) do
resources :runners, only: [:index, :edit, :update, :destroy, :show] do resources :runners, only: [:index, :edit, :update, :destroy, :show] do
member do member do
get :resume post :resume
get :pause post :pause
end end
collection do collection do
......
class FixDevTimezoneSchema < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# The this migrations tries to help solve unwanted changes to `schema.rb`
# while developing GitLab. Installations created before we started using
# `datetime_with_timezone` are likely to face this problem. Updating those
# columns to the new type should help fix this.
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
TIMEZONE_TABLES = %i(appearances ci_group_variables ci_pipeline_schedule_variables events gpg_keys gpg_signatures project_auto_devops)
def up
return unless Rails.env.development? || Rails.env.test?
TIMEZONE_TABLES.each do |table|
change_column table, :created_at, :datetime_with_timezone
change_column table, :updated_at, :datetime_with_timezone
end
end
def down
end
end
...@@ -15,8 +15,20 @@ class IssuesMovedToIdForeignKey < ActiveRecord::Migration ...@@ -15,8 +15,20 @@ class IssuesMovedToIdForeignKey < ActiveRecord::Migration
self.table_name = 'issues' self.table_name = 'issues'
def self.with_orphaned_moved_to_issues def self.with_orphaned_moved_to_issues
where('NOT EXISTS (SELECT true FROM issues WHERE issues.id = issues.moved_to_id)') if Gitlab::Database.postgresql?
# Be careful to use a second table here for comparison otherwise we'll null
# out all rows that don't have id == moved.to_id!
where('NOT EXISTS (SELECT true FROM issues B WHERE issues.moved_to_id = B.id)')
.where('moved_to_id IS NOT NULL') .where('moved_to_id IS NOT NULL')
else
# MySQL doesn't allow modification of the same table in a subquery,
# and using a temporary table isn't automatically guaranteed to work
# due to the MySQL query optimizer. See
# https://dev.mysql.com/doc/refman/5.7/en/update.html for more
# details.
joins('LEFT JOIN issues AS b ON issues.moved_to_id = b.id')
.where('issues.moved_to_id IS NOT NULL AND b.id IS NULL')
end
end end
end end
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CleanUpForMembers < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
class Member < ActiveRecord::Base
include EachBatch
self.table_name = 'members'
end
def up
condition = <<~EOF.squish
invite_token IS NULL AND
NOT EXISTS (SELECT 1 FROM users WHERE users.id = members.user_id)
EOF
Member.each_batch(of: 10_000) do |batch|
batch.where(condition).delete_all
end
end
def down
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddForeignKeyForMembers < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key(:members,
:users,
column: :user_id)
end
def down
remove_foreign_key(:members, column: :user_id)
end
end
...@@ -749,8 +749,8 @@ ActiveRecord::Schema.define(version: 20171220191323) do ...@@ -749,8 +749,8 @@ ActiveRecord::Schema.define(version: 20171220191323) do
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "confirmation_token" t.string "confirmation_token"
t.datetime "confirmed_at" t.datetime_with_timezone "confirmed_at"
t.datetime "confirmation_sent_at" t.datetime_with_timezone "confirmation_sent_at"
end end
add_index "emails", ["confirmation_token"], name: "index_emails_on_confirmation_token", unique: true, using: :btree add_index "emails", ["confirmation_token"], name: "index_emails_on_confirmation_token", unique: true, using: :btree
...@@ -2254,8 +2254,8 @@ ActiveRecord::Schema.define(version: 20171220191323) do ...@@ -2254,8 +2254,8 @@ ActiveRecord::Schema.define(version: 20171220191323) do
add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree
create_table "user_custom_attributes", force: :cascade do |t| create_table "user_custom_attributes", force: :cascade do |t|
t.datetime "created_at", null: false t.datetime_with_timezone "created_at", null: false
t.datetime "updated_at", null: false t.datetime_with_timezone "updated_at", null: false
t.integer "user_id", null: false t.integer "user_id", null: false
t.string "key", null: false t.string "key", null: false
t.string "value", null: false t.string "value", null: false
...@@ -2522,6 +2522,7 @@ ActiveRecord::Schema.define(version: 20171220191323) do ...@@ -2522,6 +2522,7 @@ ActiveRecord::Schema.define(version: 20171220191323) do
add_foreign_key "labels", "projects", name: "fk_7de4989a69", on_delete: :cascade add_foreign_key "labels", "projects", name: "fk_7de4989a69", on_delete: :cascade
add_foreign_key "lists", "boards", name: "fk_0d3f677137", on_delete: :cascade add_foreign_key "lists", "boards", name: "fk_0d3f677137", on_delete: :cascade
add_foreign_key "lists", "labels", name: "fk_7a5553d60f", on_delete: :cascade add_foreign_key "lists", "labels", name: "fk_7a5553d60f", on_delete: :cascade
add_foreign_key "members", "users", name: "fk_2e88fb7ce9", on_delete: :cascade
add_foreign_key "merge_request_diff_commits", "merge_request_diffs", on_delete: :cascade add_foreign_key "merge_request_diff_commits", "merge_request_diffs", on_delete: :cascade
add_foreign_key "merge_request_diff_files", "merge_request_diffs", on_delete: :cascade add_foreign_key "merge_request_diff_files", "merge_request_diffs", on_delete: :cascade
add_foreign_key "merge_request_diffs", "merge_requests", name: "fk_8483f3258f", on_delete: :cascade add_foreign_key "merge_request_diffs", "merge_requests", name: "fk_8483f3258f", on_delete: :cascade
......
...@@ -58,30 +58,32 @@ our AsciiDoc snippets, wikis and repos using delimited blocks: ...@@ -58,30 +58,32 @@ our AsciiDoc snippets, wikis and repos using delimited blocks:
- **Markdown** - **Markdown**
<pre>
```plantuml ```plantuml
Bob -> Alice : hello Bob -> Alice : hello
Alice -> Bob : Go Away Alice -> Bob : Go Away
``` ```
</pre>
- **AsciiDoc** - **AsciiDoc**
``` <pre>
[plantuml, format="png", id="myDiagram", width="200px"] [plantuml, format="png", id="myDiagram", width="200px"]
-- --
Bob->Alice : hello Bob->Alice : hello
Alice -> Bob : Go Away Alice -> Bob : Go Away
-- --
``` </pre>
- **reStructuredText** - **reStructuredText**
``` <pre>
.. plantuml:: .. plantuml::
:caption: Caption with **bold** and *italic* :caption: Caption with **bold** and *italic*
Bob -> Alice: hello Bob -> Alice: hello
Alice -> Bob: Go Away Alice -> Bob: Go Away
``` </pre>
You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.python.org/pypi/sphinxcontrib-plantuml), but please note that we currently only support the `caption` option. You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.python.org/pypi/sphinxcontrib-plantuml), but please note that we currently only support the `caption` option.
......
This diff is collapsed.
...@@ -16,8 +16,7 @@ codequality: ...@@ -16,8 +16,7 @@ codequality:
- docker:dind - docker:dind
script: script:
- docker pull codeclimate/codeclimate - docker pull codeclimate/codeclimate
- docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate init - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json || true
- docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json
artifacts: artifacts:
paths: [codeclimate.json] paths: [codeclimate.json]
``` ```
......
...@@ -27,6 +27,7 @@ comments: false ...@@ -27,6 +27,7 @@ comments: false
## Backend guides ## Backend guides
- [GitLab utilities](utilities.md)
- [API styleguide](api_styleguide.md) Use this styleguide if you are - [API styleguide](api_styleguide.md) Use this styleguide if you are
contributing to the API. contributing to the API.
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
......
# GitLab utilities
We developed a number of utilities to ease development.
## [`MergeHash`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/utils/merge_hash.rb)
* Deep merges an array of hashes:
``` ruby
Gitlab::Utils::MergeHash.merge(
[{ hello: ["world"] },
{ hello: "Everyone" },
{ hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] } },
"Goodbye", "Hallo"]
)
```
Gives:
``` ruby
[
{
hello:
[
"world",
"Everyone",
{ greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] }
]
},
"Goodbye"
]
```
* Extracts all keys and values from a hash into an array:
``` ruby
Gitlab::Utils::MergeHash.crush(
{ hello: "world", this: { crushes: ["an entire", "hash"] } }
)
```
Gives:
``` ruby
[:hello, "world", :this, :crushes, "an entire", "hash"]
```
## [`StrongMemoize`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/utils/strong_memoize.rb)
* Memoize the value even if it is `nil` or `false`.
We often do `@value ||= compute`, however this doesn't work well if
`compute` might eventually give `nil` and we don't want to compute again.
Instead we could use `defined?` to check if the value is set or not.
However it's tedious to write such pattern, and `StrongMemoize` would
help us use such pattern.
Instead of writing patterns like this:
``` ruby
class Find
def result
return @result if defined?(@result)
@result = search
end
end
```
We could write it like:
``` ruby
class Find
include Gitlab::Utils::StrongMemoize
def result
strong_memoize(:result) do
search
end
end
end
```
* Clear memoization
``` ruby
class Find
include Gitlab::Utils::StrongMemoize
end
Find.new.clear_memoization(:result)
```
...@@ -170,6 +170,7 @@ where `PROJECT-1` is the issue ID of the JIRA project. ...@@ -170,6 +170,7 @@ where `PROJECT-1` is the issue ID of the JIRA project.
- Only commits and merges into the project's default branch (usually **master**) will - Only commits and merges into the project's default branch (usually **master**) will
close an issue in Jira. You can change your projects default branch under close an issue in Jira. You can change your projects default branch under
[project settings](img/jira_project_settings.png). [project settings](img/jira_project_settings.png).
- The JIRA issue will not be transitioned if it has a resolution.
### JIRA issue closing example ### JIRA issue closing example
...@@ -219,6 +220,10 @@ JIRA issue references and update comments will not work if the GitLab issue trac ...@@ -219,6 +220,10 @@ JIRA issue references and update comments will not work if the GitLab issue trac
Make sure the `Transition ID` you set within the JIRA settings matches the one Make sure the `Transition ID` you set within the JIRA settings matches the one
your project needs to close a ticket. your project needs to close a ticket.
Make sure that the JIRA issue is not already marked as resolved, in other words that
the JIRA issue resolution field is not set. (It should not be struck through in
JIRA lists.)
[services-templates]: services_templates.md [services-templates]: services_templates.md
[jira-repo-old-docs]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-13-stable/doc/project_services/jira.md [jira-repo-old-docs]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-13-stable/doc/project_services/jira.md
[jira]: https://www.atlassian.com/software/jira [jira]: https://www.atlassian.com/software/jira
...@@ -41,9 +41,15 @@ do. ...@@ -41,9 +41,15 @@ do.
| `/clear_weight` | Clears the issue weight | | `/clear_weight` | Clears the issue weight |
| `/board_move ~column` | Move issue to column on the board | | `/board_move ~column` | Move issue to column on the board |
| `/duplicate #issue` | Closes this issue and marks it as a duplicate of another issue | | `/duplicate #issue` | Closes this issue and marks it as a duplicate of another issue |
<<<<<<< HEAD
| `/move path/to/project` | Moves issue to another project | | `/move path/to/project` | Moves issue to another project |
| `/tableflip` | Append the comment with `(╯°□°)╯︵ ┻━┻` | | `/tableflip` | Append the comment with `(╯°□°)╯︵ ┻━┻` |
| `/shrug` | Append the comment with `¯\_(ツ)_/¯` | | `/shrug` | Append the comment with `¯\_(ツ)_/¯` |
Note: In GitLab EES every issue can have more than one assignee, so commands `/assign`, `/unassign` and `/reassign` Note: In GitLab EES every issue can have more than one assignee, so commands `/assign`, `/unassign` and `/reassign`
support multiple assignees. support multiple assignees.
=======
| `/move path/to/project` | Moves issue to another project |
| `/tableflip` | Append the comment with `(╯°□°)╯︵ ┻━┻` |
| `/shrug` | Append the comment with `¯\_(ツ)_/¯` |
>>>>>>> upstream/master
...@@ -21,7 +21,11 @@ module SharedProject ...@@ -21,7 +21,11 @@ module SharedProject
# Create a specific project called "Shop" # Create a specific project called "Shop"
step 'I own project "Shop"' do step 'I own project "Shop"' do
@project = Project.find_by(name: "Shop") @project = Project.find_by(name: "Shop")
<<<<<<< HEAD
@project ||= create(:project, :repository, name: "Shop", namespace: @user.namespace, issues_template: "This issue should contain the following.", merge_requests_template: "This merge request should contain the following.") @project ||= create(:project, :repository, name: "Shop", namespace: @user.namespace, issues_template: "This issue should contain the following.", merge_requests_template: "This merge request should contain the following.")
=======
@project ||= create(:project, :repository, name: "Shop", namespace: @user.namespace)
>>>>>>> upstream/master
@project.add_master(@user) @project.add_master(@user)
end end
......
...@@ -29,6 +29,9 @@ Capybara.register_driver :chrome do |app| ...@@ -29,6 +29,9 @@ Capybara.register_driver :chrome do |app|
options.add_argument("disable-gpu") options.add_argument("disable-gpu")
end end
# Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252
options.add_argument("disable-dev-shm-usage") if ENV['CI'] || ENV['CI_SERVER']
Capybara::Selenium::Driver.new( Capybara::Selenium::Driver.new(
app, app,
browser: :chrome, browser: :chrome,
......
...@@ -786,8 +786,9 @@ module API ...@@ -786,8 +786,9 @@ module API
class ProjectService < Grape::Entity class ProjectService < Grape::Entity
expose :id, :title, :created_at, :updated_at, :active expose :id, :title, :created_at, :updated_at, :active
expose :push_events, :issues_events, :merge_requests_events expose :push_events, :issues_events, :confidential_issues_events
expose :tag_push_events, :note_events, :pipeline_events expose :merge_requests_events, :tag_push_events, :note_events
expose :pipeline_events, :wiki_page_events
expose :job_events expose :job_events
# Expose serialized properties # Expose serialized properties
expose :properties do |service, options| expose :properties do |service, options|
......
...@@ -202,9 +202,12 @@ module API ...@@ -202,9 +202,12 @@ module API
project = Gitlab::GlRepository.parse(params[:gl_repository]).first project = Gitlab::GlRepository.parse(params[:gl_repository]).first
user = identify(params[:identifier]) user = identify(params[:identifier])
# A user is not guaranteed to be returned; an orphaned write deploy
# key could be used
if user
redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id) redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id)
if redirect_message output[:redirected_message] = redirect_message if redirect_message
output[:redirected_message] = redirect_message
end end
output output
......
...@@ -65,7 +65,9 @@ module API ...@@ -65,7 +65,9 @@ module API
member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at]) member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at])
if member.persisted? && member.valid? if !member
not_allowed! # This currently can only be reached in EE
elsif member.persisted? && member.valid?
present member.user, with: Entities::Member, member: member present member.user, with: Entities::Member, member: member
else else
render_validation_error!(member) render_validation_error!(member)
......
module API module API
class Services < Grape::API class Services < Grape::API
chat_notification_settings = [
{
required: true,
name: :webhook,
type: String,
desc: 'The chat webhook'
},
{
required: false,
name: :username,
type: String,
desc: 'The chat username'
},
{
required: false,
name: :channel,
type: String,
desc: 'The default chat channel'
}
]
chat_notification_flags = [
{
required: false,
name: :notify_only_broken_pipelines,
type: Boolean,
desc: 'Send notifications for broken pipelines'
},
{
required: false,
name: :notify_only_default_branch,
type: Boolean,
desc: 'Send notifications only for the default branch'
}
]
chat_notification_channels = [
{
required: false,
name: :push_channel,
type: String,
desc: 'The name of the channel to receive push_events notifications'
},
{
required: false,
name: :issue_channel,
type: String,
desc: 'The name of the channel to receive issues_events notifications'
},
{
required: false,
name: :confidential_issue_channel,
type: String,
desc: 'The name of the channel to receive confidential_issues_events notifications'
},
{
required: false,
name: :merge_request_channel,
type: String,
desc: 'The name of the channel to receive merge_requests_events notifications'
},
{
required: false,
name: :note_channel,
type: String,
desc: 'The name of the channel to receive note_events notifications'
},
{
required: false,
name: :tag_push_channel,
type: String,
desc: 'The name of the channel to receive tag_push_events notifications'
},
{
required: false,
name: :pipeline_channel,
type: String,
desc: 'The name of the channel to receive pipeline_events notifications'
},
{
required: false,
name: :wiki_page_channel,
type: String,
desc: 'The name of the channel to receive wiki_page_events notifications'
}
]
chat_notification_events = [
{
required: false,
name: :push_events,
type: Boolean,
desc: 'Enable notifications for push_events'
},
{
required: false,
name: :issues_events,
type: Boolean,
desc: 'Enable notifications for issues_events'
},
{
required: false,
name: :confidential_issues_events,
type: Boolean,
desc: 'Enable notifications for confidential_issues_events'
},
{
required: false,
name: :merge_requests_events,
type: Boolean,
desc: 'Enable notifications for merge_requests_events'
},
{
required: false,
name: :note_events,
type: Boolean,
desc: 'Enable notifications for note_events'
},
{
required: false,
name: :tag_push_events,
type: Boolean,
desc: 'Enable notifications for tag_push_events'
},
{
required: false,
name: :pipeline_events,
type: Boolean,
desc: 'Enable notifications for pipeline_events'
},
{
required: false,
name: :wiki_page_events,
type: Boolean,
desc: 'Enable notifications for wiki_page_events'
}
]
services = { services = {
'asana' => [ 'asana' => [
{ {
...@@ -488,25 +626,11 @@ module API ...@@ -488,25 +626,11 @@ module API
} }
], ],
'slack' => [ 'slack' => [
{ chat_notification_settings,
required: true, chat_notification_flags,
name: :webhook, chat_notification_channels,
type: String, chat_notification_events
desc: 'The Slack webhook. e.g. https://hooks.slack.com/services/...' ].flatten,
},
{
required: false,
name: :new_issue_url,
type: String,
desc: 'The user name'
},
{
required: false,
name: :channel,
type: String,
desc: 'The channel name'
}
],
'microsoft-teams' => [ 'microsoft-teams' => [
{ {
required: true, required: true,
...@@ -516,19 +640,11 @@ module API ...@@ -516,19 +640,11 @@ module API
} }
], ],
'mattermost' => [ 'mattermost' => [
{ chat_notification_settings,
required: true, chat_notification_flags,
name: :webhook, chat_notification_channels,
type: String, chat_notification_events
desc: 'The Mattermost webhook. e.g. http://mattermost_host/hooks/...' ].flatten,
},
{
required: false,
name: :username,
type: String,
desc: 'The username to use to post the message'
}
],
'teamcity' => [ 'teamcity' => [
{ {
required: true, required: true,
......
...@@ -18,7 +18,7 @@ module Backup ...@@ -18,7 +18,7 @@ module Backup
FileUtils.rm_f(backup_tarball) FileUtils.rm_f(backup_tarball)
if ENV['STRATEGY'] == 'copy' if ENV['STRATEGY'] == 'copy'
cmd = %W(cp -a #{app_files_dir} #{Gitlab.config.backup.path}) cmd = %W(rsync -a --exclude=lost+found #{app_files_dir} #{Gitlab.config.backup.path})
output, status = Gitlab::Popen.popen(cmd) output, status = Gitlab::Popen.popen(cmd)
unless status.zero? unless status.zero?
...@@ -26,10 +26,10 @@ module Backup ...@@ -26,10 +26,10 @@ module Backup
abort 'Backup failed' abort 'Backup failed'
end end
run_pipeline!([%W(tar -C #{@backup_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600]) run_pipeline!([%W(tar --exclude=lost+found -C #{@backup_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600])
FileUtils.rm_rf(@backup_files_dir) FileUtils.rm_rf(@backup_files_dir)
else else
run_pipeline!([%W(tar -C #{app_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600]) run_pipeline!([%W(tar --exclude=lost+found -C #{app_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600])
end end
end end
......
...@@ -66,7 +66,7 @@ module Banzai ...@@ -66,7 +66,7 @@ module Banzai
if uri.relative? && uri.path.present? if uri.relative? && uri.path.present?
html_attr.value = rebuild_relative_uri(uri).to_s html_attr.value = rebuild_relative_uri(uri).to_s
end end
rescue URI::Error rescue URI::Error, Addressable::URI::InvalidURIError
# noop # noop
end end
......
...@@ -21,6 +21,10 @@ module Gitlab ...@@ -21,6 +21,10 @@ module Gitlab
end end
def add_redirect_message def add_redirect_message
# Don't bother with sending a redirect message for anonymous clones
# because they never see it via the `/internal/post_receive` endpoint
return unless user.present? && project.present?
Gitlab::Redis::SharedState.with do |redis| Gitlab::Redis::SharedState.with do |redis|
key = self.class.redirect_message_key(user.id, project.id) key = self.class.redirect_message_key(user.id, project.id)
redis.setex(key, 5.minutes, redirect_message) redis.setex(key, 5.minutes, redirect_message)
......
...@@ -13,12 +13,13 @@ module Gitlab ...@@ -13,12 +13,13 @@ module Gitlab
end end
def resolve(user, commit_message, files) def resolve(user, commit_message, files)
msg = commit_message || default_commit_message
resolution = Gitlab::Git::Conflict::Resolution.new(user, files, msg)
args = { args = {
source_branch: merge_request.source_branch, source_branch: merge_request.source_branch,
target_branch: merge_request.target_branch, target_branch: merge_request.target_branch
commit_message: commit_message || default_commit_message
} }
resolver.resolve_conflicts(@source_repo, user, files, args) resolver.resolve_conflicts(@source_repo, resolution, args)
ensure ensure
@merge_request.clear_memoized_shas @merge_request.clear_memoized_shas
end end
......
...@@ -71,6 +71,16 @@ module Gitlab ...@@ -71,6 +71,16 @@ module Gitlab
end end
end end
def encode_binary(s)
return "" if s.nil?
s.dup.force_encoding(Encoding::ASCII_8BIT)
end
def binary_stringio(s)
StringIO.new(s || '').tap { |io| io.set_encoding(Encoding::ASCII_8BIT) }
end
private private
def clean(message) def clean(message)
......
...@@ -2,7 +2,9 @@ module Gitlab ...@@ -2,7 +2,9 @@ module Gitlab
module Git module Git
module Conflict module Conflict
class File class File
attr_reader :content, :their_path, :our_path, :our_mode, :repository, :commit_oid attr_reader :their_path, :our_path, :our_mode, :repository, :commit_oid
attr_accessor :content
def initialize(repository, commit_oid, conflict, content) def initialize(repository, commit_oid, conflict, content)
@repository = repository @repository = repository
......
module Gitlab
module Git
module Conflict
class Resolution
attr_reader :user, :files, :commit_message
def initialize(user, files, commit_message)
@user = user
@files = files
@commit_message = commit_message
end
end
end
end
end
...@@ -13,37 +13,27 @@ module Gitlab ...@@ -13,37 +13,27 @@ module Gitlab
def conflicts def conflicts
@conflicts ||= begin @conflicts ||= begin
target_index = @target_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid) @target_repository.gitaly_migrate(:conflicts_list_conflict_files) do |is_enabled|
if is_enabled
# We don't need to do `with_repo_branch_commit` here, because the target gitaly_conflicts_client(@target_repository).list_conflict_files
# project always fetches source refs when creating merge request diffs. else
conflict_files(@target_repository, target_index) rugged_list_conflict_files
end end
end end
def resolve_conflicts(source_repository, user, files, source_branch:, target_branch:, commit_message:)
source_repository.with_repo_branch_commit(@target_repository, target_branch) do
index = source_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid)
conflicts = conflict_files(source_repository, index)
files.each do |file_params|
conflict_file = conflict_for_path(conflicts, file_params[:old_path], file_params[:new_path])
write_resolved_file_to_index(source_repository, index, conflict_file, file_params)
end end
rescue GRPC::FailedPrecondition => e
unless index.conflicts.empty? raise Gitlab::Git::Conflict::Resolver::ConflictSideMissing.new(e.message)
missing_files = index.conflicts.map { |file| file[:ours][:path] } rescue Rugged::OdbError, GRPC::BadStatus => e
raise Gitlab::Git::CommandError.new(e)
raise ResolutionError, "Missing resolutions for the following files: #{missing_files.join(', ')}"
end end
commit_params = { def resolve_conflicts(source_repository, resolution, source_branch:, target_branch:)
message: commit_message, source_repository.gitaly_migrate(:conflicts_resolve_conflicts) do |is_enabled|
parents: [@our_commit_oid, @their_commit_oid] if is_enabled
} gitaly_conflicts_client(source_repository).resolve_conflicts(@target_repository, resolution, source_branch, target_branch)
else
source_repository.commit_index(user, source_branch, index, commit_params) rugged_resolve_conflicts(source_repository, resolution, source_branch, target_branch)
end
end end
end end
...@@ -68,6 +58,10 @@ module Gitlab ...@@ -68,6 +58,10 @@ module Gitlab
end end
end end
def gitaly_conflicts_client(repository)
repository.gitaly_conflicts_client(@our_commit_oid, @their_commit_oid)
end
def write_resolved_file_to_index(repository, index, file, params) def write_resolved_file_to_index(repository, index, file, params)
if params[:sections] if params[:sections]
resolved_lines = file.resolve_lines(params[:sections]) resolved_lines = file.resolve_lines(params[:sections])
...@@ -84,6 +78,40 @@ module Gitlab ...@@ -84,6 +78,40 @@ module Gitlab
index.add(path: our_path, oid: oid, mode: file.our_mode) index.add(path: our_path, oid: oid, mode: file.our_mode)
index.conflict_remove(our_path) index.conflict_remove(our_path)
end end
def rugged_list_conflict_files
target_index = @target_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid)
# We don't need to do `with_repo_branch_commit` here, because the target
# project always fetches source refs when creating merge request diffs.
conflict_files(@target_repository, target_index)
end
def rugged_resolve_conflicts(source_repository, resolution, source_branch, target_branch)
source_repository.with_repo_branch_commit(@target_repository, target_branch) do
index = source_repository.rugged.merge_commits(@our_commit_oid, @their_commit_oid)
conflicts = conflict_files(source_repository, index)
resolution.files.each do |file_params|
conflict_file = conflict_for_path(conflicts, file_params[:old_path], file_params[:new_path])
write_resolved_file_to_index(source_repository, index, conflict_file, file_params)
end
unless index.conflicts.empty?
missing_files = index.conflicts.map { |file| file[:ours][:path] }
raise ResolutionError, "Missing resolutions for the following files: #{missing_files.join(', ')}"
end
commit_params = {
message: resolution.commit_message,
parents: [@our_commit_oid, @their_commit_oid]
}
source_repository.commit_index(resolution.user, source_branch, index, commit_params)
end
end
end end
end end
end end
......
...@@ -126,7 +126,7 @@ module Gitlab ...@@ -126,7 +126,7 @@ module Gitlab
end end
def exists? def exists?
Gitlab::GitalyClient.migrate(:repository_exists, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled| Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
if enabled if enabled
gitaly_repository_client.exists? gitaly_repository_client.exists?
else else
...@@ -188,7 +188,7 @@ module Gitlab ...@@ -188,7 +188,7 @@ module Gitlab
end end
def local_branches(sort_by: nil) def local_branches(sort_by: nil)
gitaly_migrate(:local_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| gitaly_migrate(:local_branches) do |is_enabled|
if is_enabled if is_enabled
gitaly_ref_client.local_branches(sort_by: sort_by) gitaly_ref_client.local_branches(sort_by: sort_by)
else else
...@@ -919,31 +919,23 @@ module Gitlab ...@@ -919,31 +919,23 @@ module Gitlab
# If `mirror_refmap` is present the remote is set as mirror with that mapping # If `mirror_refmap` is present the remote is set as mirror with that mapping
def add_remote(remote_name, url, mirror_refmap: nil) def add_remote(remote_name, url, mirror_refmap: nil)
rugged.remotes.create(remote_name, url) gitaly_migrate(:remote_add_remote) do |is_enabled|
if is_enabled
set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap gitaly_remote_client.add_remote(remote_name, url, mirror_refmap)
rescue Rugged::ConfigError else
remote_update(remote_name, url: url) rugged_add_remote(remote_name, url, mirror_refmap)
end
end
end end
def remove_remote(remote_name) def remove_remote(remote_name)
# When a remote is deleted all its remote refs are deleted too, but in gitaly_migrate(:remote_remove_remote) do |is_enabled|
# the case of mirrors we map its refs (that would usualy go under if is_enabled
# [remote_name]/) to the top level namespace. We clean the mapping so gitaly_remote_client.remove_remote(remote_name)
# those don't get deleted. else
if rugged.config["remote.#{remote_name}.mirror"] rugged_remove_remote(remote_name)
rugged.config.delete("remote.#{remote_name}.fetch")
end end
rugged.remotes.delete(remote_name)
true
rescue Rugged::ConfigError
false
end end
# Returns true if a remote exists.
def remote_exists?(name)
rugged.remotes[name].present?
end end
# Update the specified remote using the values in the +options+ hash # Update the specified remote using the values in the +options+ hash
...@@ -1298,6 +1290,14 @@ module Gitlab ...@@ -1298,6 +1290,14 @@ module Gitlab
@gitaly_operation_client ||= Gitlab::GitalyClient::OperationService.new(self) @gitaly_operation_client ||= Gitlab::GitalyClient::OperationService.new(self)
end end
def gitaly_remote_client
@gitaly_remote_client ||= Gitlab::GitalyClient::RemoteService.new(self)
end
def gitaly_conflicts_client(our_commit_oid, their_commit_oid)
Gitlab::GitalyClient::ConflictsService.new(self, our_commit_oid, their_commit_oid)
end
def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block) def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
Gitlab::GitalyClient.migrate(method, status: status, &block) Gitlab::GitalyClient.migrate(method, status: status, &block)
rescue GRPC::NotFound => e rescue GRPC::NotFound => e
...@@ -1917,6 +1917,29 @@ module Gitlab ...@@ -1917,6 +1917,29 @@ module Gitlab
raise ArgumentError, 'Invalid merge source' raise ArgumentError, 'Invalid merge source'
end end
def rugged_add_remote(remote_name, url, mirror_refmap)
rugged.remotes.create(remote_name, url)
set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap
rescue Rugged::ConfigError
remote_update(remote_name, url: url)
end
def rugged_remove_remote(remote_name)
# When a remote is deleted all its remote refs are deleted too, but in
# the case of mirrors we map its refs (that would usualy go under
# [remote_name]/) to the top level namespace. We clean the mapping so
# those don't get deleted.
if rugged.config["remote.#{remote_name}.mirror"]
rugged.config.delete("remote.#{remote_name}.fetch")
end
rugged.remotes.delete(remote_name)
true
rescue Rugged::ConfigError
false
end
def fetch_remote(remote_name = 'origin', env: nil) def fetch_remote(remote_name = 'origin', env: nil)
run_git(['fetch', remote_name], env: env).last.zero? run_git(['fetch', remote_name], env: env).last.zero?
end end
......
...@@ -330,22 +330,6 @@ module Gitlab ...@@ -330,22 +330,6 @@ module Gitlab
Google::Protobuf::Timestamp.new(seconds: t.to_i) Google::Protobuf::Timestamp.new(seconds: t.to_i)
end end
def self.encode(s)
return "" if s.nil?
s.dup.force_encoding(Encoding::ASCII_8BIT)
end
def self.binary_stringio(s)
io = StringIO.new(s || '')
io.set_encoding(Encoding::ASCII_8BIT)
io
end
def self.encode_repeated(a)
Google::Protobuf::RepeatedField.new(:bytes, a.map { |s| self.encode(s) } )
end
# The default timeout on all Gitaly calls # The default timeout on all Gitaly calls
def self.default_timeout def self.default_timeout
return 0 if Sidekiq.server? return 0 if Sidekiq.server?
......
module Gitlab module Gitlab
module GitalyClient module GitalyClient
class CommitService class CommitService
include Gitlab::EncodingHelper
# The ID of empty tree. # The ID of empty tree.
# See http://stackoverflow.com/a/40884093/1856239 and https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012 # See http://stackoverflow.com/a/40884093/1856239 and https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012
EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze
...@@ -13,7 +15,7 @@ module Gitlab ...@@ -13,7 +15,7 @@ module Gitlab
def ls_files(revision) def ls_files(revision)
request = Gitaly::ListFilesRequest.new( request = Gitaly::ListFilesRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision) revision: encode_binary(revision)
) )
response = GitalyClient.call(@repository.storage, :commit_service, :list_files, request, timeout: GitalyClient.medium_timeout) response = GitalyClient.call(@repository.storage, :commit_service, :list_files, request, timeout: GitalyClient.medium_timeout)
...@@ -73,7 +75,7 @@ module Gitlab ...@@ -73,7 +75,7 @@ module Gitlab
request = Gitaly::TreeEntryRequest.new( request = Gitaly::TreeEntryRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: ref, revision: ref,
path: GitalyClient.encode(path), path: encode_binary(path),
limit: limit.to_i limit: limit.to_i
) )
...@@ -98,8 +100,8 @@ module Gitlab ...@@ -98,8 +100,8 @@ module Gitlab
def tree_entries(repository, revision, path) def tree_entries(repository, revision, path)
request = Gitaly::GetTreeEntriesRequest.new( request = Gitaly::GetTreeEntriesRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision), revision: encode_binary(revision),
path: path.present? ? GitalyClient.encode(path) : '.' path: path.present? ? encode_binary(path) : '.'
) )
response = GitalyClient.call(@repository.storage, :commit_service, :get_tree_entries, request, timeout: GitalyClient.medium_timeout) response = GitalyClient.call(@repository.storage, :commit_service, :get_tree_entries, request, timeout: GitalyClient.medium_timeout)
...@@ -112,8 +114,8 @@ module Gitlab ...@@ -112,8 +114,8 @@ module Gitlab
type: gitaly_tree_entry.type.downcase, type: gitaly_tree_entry.type.downcase,
mode: gitaly_tree_entry.mode.to_s(8), mode: gitaly_tree_entry.mode.to_s(8),
name: File.basename(gitaly_tree_entry.path), name: File.basename(gitaly_tree_entry.path),
path: GitalyClient.encode(gitaly_tree_entry.path), path: encode_binary(gitaly_tree_entry.path),
flat_path: GitalyClient.encode(gitaly_tree_entry.flat_path), flat_path: encode_binary(gitaly_tree_entry.flat_path),
commit_id: gitaly_tree_entry.commit_oid commit_id: gitaly_tree_entry.commit_oid
) )
end end
...@@ -135,8 +137,8 @@ module Gitlab ...@@ -135,8 +137,8 @@ module Gitlab
def last_commit_for_path(revision, path) def last_commit_for_path(revision, path)
request = Gitaly::LastCommitForPathRequest.new( request = Gitaly::LastCommitForPathRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision), revision: encode_binary(revision),
path: GitalyClient.encode(path.to_s) path: encode_binary(path.to_s)
) )
gitaly_commit = GitalyClient.call(@repository.storage, :commit_service, :last_commit_for_path, request, timeout: GitalyClient.fast_timeout).commit gitaly_commit = GitalyClient.call(@repository.storage, :commit_service, :last_commit_for_path, request, timeout: GitalyClient.fast_timeout).commit
...@@ -202,8 +204,8 @@ module Gitlab ...@@ -202,8 +204,8 @@ module Gitlab
def raw_blame(revision, path) def raw_blame(revision, path)
request = Gitaly::RawBlameRequest.new( request = Gitaly::RawBlameRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision), revision: encode_binary(revision),
path: GitalyClient.encode(path) path: encode_binary(path)
) )
response = GitalyClient.call(@repository.storage, :commit_service, :raw_blame, request, timeout: GitalyClient.medium_timeout) response = GitalyClient.call(@repository.storage, :commit_service, :raw_blame, request, timeout: GitalyClient.medium_timeout)
...@@ -213,7 +215,7 @@ module Gitlab ...@@ -213,7 +215,7 @@ module Gitlab
def find_commit(revision) def find_commit(revision)
request = Gitaly::FindCommitRequest.new( request = Gitaly::FindCommitRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision) revision: encode_binary(revision)
) )
response = GitalyClient.call(@repository.storage, :commit_service, :find_commit, request, timeout: GitalyClient.medium_timeout) response = GitalyClient.call(@repository.storage, :commit_service, :find_commit, request, timeout: GitalyClient.medium_timeout)
...@@ -224,7 +226,7 @@ module Gitlab ...@@ -224,7 +226,7 @@ module Gitlab
def patch(revision) def patch(revision)
request = Gitaly::CommitPatchRequest.new( request = Gitaly::CommitPatchRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision) revision: encode_binary(revision)
) )
response = GitalyClient.call(@repository.storage, :diff_service, :commit_patch, request, timeout: GitalyClient.medium_timeout) response = GitalyClient.call(@repository.storage, :diff_service, :commit_patch, request, timeout: GitalyClient.medium_timeout)
...@@ -234,7 +236,7 @@ module Gitlab ...@@ -234,7 +236,7 @@ module Gitlab
def commit_stats(revision) def commit_stats(revision)
request = Gitaly::CommitStatsRequest.new( request = Gitaly::CommitStatsRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: GitalyClient.encode(revision) revision: encode_binary(revision)
) )
GitalyClient.call(@repository.storage, :commit_service, :commit_stats, request, timeout: GitalyClient.medium_timeout) GitalyClient.call(@repository.storage, :commit_service, :commit_stats, request, timeout: GitalyClient.medium_timeout)
end end
...@@ -250,9 +252,9 @@ module Gitlab ...@@ -250,9 +252,9 @@ module Gitlab
) )
request.after = GitalyClient.timestamp(options[:after]) if options[:after] request.after = GitalyClient.timestamp(options[:after]) if options[:after]
request.before = GitalyClient.timestamp(options[:before]) if options[:before] request.before = GitalyClient.timestamp(options[:before]) if options[:before]
request.revision = GitalyClient.encode(options[:ref]) if options[:ref] request.revision = encode_binary(options[:ref]) if options[:ref]
request.paths = GitalyClient.encode_repeated(Array(options[:path])) if options[:path].present? request.paths = encode_repeated(Array(options[:path])) if options[:path].present?
response = GitalyClient.call(@repository.storage, :commit_service, :find_commits, request, timeout: GitalyClient.medium_timeout) response = GitalyClient.call(@repository.storage, :commit_service, :find_commits, request, timeout: GitalyClient.medium_timeout)
...@@ -264,7 +266,7 @@ module Gitlab ...@@ -264,7 +266,7 @@ module Gitlab
enum = Enumerator.new do |y| enum = Enumerator.new do |y|
shas.each_slice(20) do |revs| shas.each_slice(20) do |revs|
request.shas = GitalyClient.encode_repeated(revs) request.shas = encode_repeated(revs)
y.yield request y.yield request
...@@ -303,7 +305,7 @@ module Gitlab ...@@ -303,7 +305,7 @@ module Gitlab
repository: @gitaly_repo, repository: @gitaly_repo,
left_commit_id: from_id, left_commit_id: from_id,
right_commit_id: to_id, right_commit_id: to_id,
paths: options.fetch(:paths, []).compact.map { |path| GitalyClient.encode(path) } paths: options.fetch(:paths, []).compact.map { |path| encode_binary(path) }
} }
end end
...@@ -314,6 +316,10 @@ module Gitlab ...@@ -314,6 +316,10 @@ module Gitlab
end end
end end
end end
def encode_repeated(a)
Google::Protobuf::RepeatedField.new(:bytes, a.map { |s| encode_binary(s) } )
end
end end
end end
end end
module Gitlab
module GitalyClient
class ConflictsService
MAX_MSG_SIZE = 128.kilobytes.freeze
def initialize(repository, our_commit_oid, their_commit_oid)
@gitaly_repo = repository.gitaly_repository
@repository = repository
@our_commit_oid = our_commit_oid
@their_commit_oid = their_commit_oid
end
def list_conflict_files
request = Gitaly::ListConflictFilesRequest.new(
repository: @gitaly_repo,
our_commit_oid: @our_commit_oid,
their_commit_oid: @their_commit_oid
)
response = GitalyClient.call(@repository.storage, :conflicts_service, :list_conflict_files, request)
files_from_response(response).to_a
end
def resolve_conflicts(target_repository, resolution, source_branch, target_branch)
reader = GitalyClient.binary_stringio(resolution.files.to_json)
req_enum = Enumerator.new do |y|
header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch)
y.yield Gitaly::ResolveConflictsRequest.new(header: header)
until reader.eof?
chunk = reader.read(MAX_MSG_SIZE)
y.yield Gitaly::ResolveConflictsRequest.new(files_json: chunk)
end
end
response = GitalyClient.call(@repository.storage, :conflicts_service, :resolve_conflicts, req_enum, remote_storage: target_repository.storage)
if response.resolution_error.present?
raise Gitlab::Git::Conflict::Resolver::ResolutionError, response.resolution_error
end
end
private
def resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch)
Gitaly::ResolveConflictsRequestHeader.new(
repository: @gitaly_repo,
our_commit_oid: @our_commit_oid,
target_repository: target_repository.gitaly_repository,
their_commit_oid: @their_commit_oid,
source_branch: source_branch,
target_branch: target_branch,
commit_message: resolution.commit_message,
user: Gitlab::Git::User.from_gitlab(resolution.user).to_gitaly
)
end
def files_from_response(response)
files = []
response.each do |msg|
msg.files.each do |gitaly_file|
if gitaly_file.header
files << file_from_gitaly_header(gitaly_file.header)
else
files.last.content << gitaly_file.content
end
end
end
files
end
def file_from_gitaly_header(header)
Gitlab::Git::Conflict::File.new(
Gitlab::GitalyClient::Util.git_repository(header.repository),
header.commit_oid,
conflict_from_gitaly_file_header(header),
''
)
end
def conflict_from_gitaly_file_header(header)
{
ours: { path: header.our_path, mode: header.our_mode },
theirs: { path: header.their_path }
}
end
end
end
end
module Gitlab module Gitlab
module GitalyClient module GitalyClient
class OperationService class OperationService
include Gitlab::EncodingHelper
def initialize(repository) def initialize(repository)
@gitaly_repo = repository.gitaly_repository @gitaly_repo = repository.gitaly_repository
@repository = repository @repository = repository
...@@ -9,7 +11,7 @@ module Gitlab ...@@ -9,7 +11,7 @@ module Gitlab
def rm_tag(tag_name, user) def rm_tag(tag_name, user)
request = Gitaly::UserDeleteTagRequest.new( request = Gitaly::UserDeleteTagRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
tag_name: GitalyClient.encode(tag_name), tag_name: encode_binary(tag_name),
user: Gitlab::Git::User.from_gitlab(user).to_gitaly user: Gitlab::Git::User.from_gitlab(user).to_gitaly
) )
...@@ -24,9 +26,9 @@ module Gitlab ...@@ -24,9 +26,9 @@ module Gitlab
request = Gitaly::UserCreateTagRequest.new( request = Gitaly::UserCreateTagRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly, user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
tag_name: GitalyClient.encode(tag_name), tag_name: encode_binary(tag_name),
target_revision: GitalyClient.encode(target), target_revision: encode_binary(target),
message: GitalyClient.encode(message.to_s) message: encode_binary(message.to_s)
) )
response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request) response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request)
...@@ -44,9 +46,9 @@ module Gitlab ...@@ -44,9 +46,9 @@ module Gitlab
def user_create_branch(branch_name, user, start_point) def user_create_branch(branch_name, user, start_point)
request = Gitaly::UserCreateBranchRequest.new( request = Gitaly::UserCreateBranchRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
branch_name: GitalyClient.encode(branch_name), branch_name: encode_binary(branch_name),
user: Gitlab::Git::User.from_gitlab(user).to_gitaly, user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
start_point: GitalyClient.encode(start_point) start_point: encode_binary(start_point)
) )
response = GitalyClient.call(@repository.storage, :operation_service, response = GitalyClient.call(@repository.storage, :operation_service,
:user_create_branch, request) :user_create_branch, request)
...@@ -64,7 +66,7 @@ module Gitlab ...@@ -64,7 +66,7 @@ module Gitlab
def user_delete_branch(branch_name, user) def user_delete_branch(branch_name, user)
request = Gitaly::UserDeleteBranchRequest.new( request = Gitaly::UserDeleteBranchRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
branch_name: GitalyClient.encode(branch_name), branch_name: encode_binary(branch_name),
user: Gitlab::Git::User.from_gitlab(user).to_gitaly user: Gitlab::Git::User.from_gitlab(user).to_gitaly
) )
...@@ -89,8 +91,8 @@ module Gitlab ...@@ -89,8 +91,8 @@ module Gitlab
repository: @gitaly_repo, repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly, user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit_id: source_sha, commit_id: source_sha,
branch: GitalyClient.encode(target_branch), branch: encode_binary(target_branch),
message: GitalyClient.encode(message) message: encode_binary(message)
) )
) )
...@@ -111,7 +113,7 @@ module Gitlab ...@@ -111,7 +113,7 @@ module Gitlab
repository: @gitaly_repo, repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly, user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit_id: source_sha, commit_id: source_sha,
branch: GitalyClient.encode(target_branch) branch: encode_binary(target_branch)
) )
branch_update = GitalyClient.call( branch_update = GitalyClient.call(
...@@ -152,9 +154,9 @@ module Gitlab ...@@ -152,9 +154,9 @@ module Gitlab
repository: @gitaly_repo, repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly, user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit: commit.to_gitaly_commit, commit: commit.to_gitaly_commit,
branch_name: GitalyClient.encode(branch_name), branch_name: encode_binary(branch_name),
message: GitalyClient.encode(message), message: encode_binary(message),
start_branch_name: GitalyClient.encode(start_branch_name.to_s), start_branch_name: encode_binary(start_branch_name.to_s),
start_repository: start_repository.gitaly_repository start_repository: start_repository.gitaly_repository
) )
......
...@@ -72,7 +72,7 @@ module Gitlab ...@@ -72,7 +72,7 @@ module Gitlab
end end
def ref_exists?(ref_name) def ref_exists?(ref_name)
request = Gitaly::RefExistsRequest.new(repository: @gitaly_repo, ref: GitalyClient.encode(ref_name)) request = Gitaly::RefExistsRequest.new(repository: @gitaly_repo, ref: encode_binary(ref_name))
response = GitalyClient.call(@storage, :ref_service, :ref_exists, request) response = GitalyClient.call(@storage, :ref_service, :ref_exists, request)
response.value response.value
rescue GRPC::InvalidArgument => e rescue GRPC::InvalidArgument => e
...@@ -82,7 +82,7 @@ module Gitlab ...@@ -82,7 +82,7 @@ module Gitlab
def find_branch(branch_name) def find_branch(branch_name)
request = Gitaly::FindBranchRequest.new( request = Gitaly::FindBranchRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
name: GitalyClient.encode(branch_name) name: encode_binary(branch_name)
) )
response = GitalyClient.call(@repository.storage, :ref_service, :find_branch, request) response = GitalyClient.call(@repository.storage, :ref_service, :find_branch, request)
...@@ -96,8 +96,8 @@ module Gitlab ...@@ -96,8 +96,8 @@ module Gitlab
def create_branch(ref, start_point) def create_branch(ref, start_point)
request = Gitaly::CreateBranchRequest.new( request = Gitaly::CreateBranchRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
name: GitalyClient.encode(ref), name: encode_binary(ref),
start_point: GitalyClient.encode(start_point) start_point: encode_binary(start_point)
) )
response = GitalyClient.call(@repository.storage, :ref_service, :create_branch, request) response = GitalyClient.call(@repository.storage, :ref_service, :create_branch, request)
...@@ -121,7 +121,7 @@ module Gitlab ...@@ -121,7 +121,7 @@ module Gitlab
def delete_branch(branch_name) def delete_branch(branch_name)
request = Gitaly::DeleteBranchRequest.new( request = Gitaly::DeleteBranchRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
name: GitalyClient.encode(branch_name) name: encode_binary(branch_name)
) )
GitalyClient.call(@repository.storage, :ref_service, :delete_branch, request) GitalyClient.call(@repository.storage, :ref_service, :delete_branch, request)
......
module Gitlab
module GitalyClient
class RemoteService
def initialize(repository)
@repository = repository
@gitaly_repo = repository.gitaly_repository
@storage = repository.storage
end
def add_remote(name, url, mirror_refmap)
request = Gitaly::AddRemoteRequest.new(
repository: @gitaly_repo, name: name, url: url,
mirror_refmap: mirror_refmap.to_s
)
GitalyClient.call(@storage, :remote_service, :add_remote, request)
end
def remove_remote(name)
request = Gitaly::RemoveRemoteRequest.new(repository: @gitaly_repo, name: name)
response = GitalyClient.call(@storage, :remote_service, :remove_remote, request)
response.result
end
end
end
end
module Gitlab module Gitlab
module GitalyClient module GitalyClient
class RepositoryService class RepositoryService
include Gitlab::EncodingHelper
def initialize(repository) def initialize(repository)
@repository = repository @repository = repository
@gitaly_repo = repository.gitaly_repository @gitaly_repo = repository.gitaly_repository
...@@ -72,7 +74,7 @@ module Gitlab ...@@ -72,7 +74,7 @@ module Gitlab
def find_merge_base(*revisions) def find_merge_base(*revisions)
request = Gitaly::FindMergeBaseRequest.new( request = Gitaly::FindMergeBaseRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revisions: revisions.map { |r| GitalyClient.encode(r) } revisions: revisions.map { |r| encode_binary(r) }
) )
response = GitalyClient.call(@storage, :repository_service, :find_merge_base, request) response = GitalyClient.call(@storage, :repository_service, :find_merge_base, request)
......
...@@ -18,6 +18,12 @@ module Gitlab ...@@ -18,6 +18,12 @@ module Gitlab
) )
end end
def git_repository(gitaly_repository)
Gitlab::Git::Repository.new(gitaly_repository.storage_name,
gitaly_repository.relative_path,
gitaly_repository.gl_repository)
end
def gitlab_tag_from_gitaly_tag(repository, gitaly_tag) def gitlab_tag_from_gitaly_tag(repository, gitaly_tag)
if gitaly_tag.target_commit.present? if gitaly_tag.target_commit.present?
commit = Gitlab::Git::Commit.decorate(repository, gitaly_tag.target_commit) commit = Gitlab::Git::Commit.decorate(repository, gitaly_tag.target_commit)
......
...@@ -3,6 +3,8 @@ require 'stringio' ...@@ -3,6 +3,8 @@ require 'stringio'
module Gitlab module Gitlab
module GitalyClient module GitalyClient
class WikiService class WikiService
include Gitlab::EncodingHelper
MAX_MSG_SIZE = 128.kilobytes.freeze MAX_MSG_SIZE = 128.kilobytes.freeze
def initialize(repository) def initialize(repository)
...@@ -13,12 +15,12 @@ module Gitlab ...@@ -13,12 +15,12 @@ module Gitlab
def write_page(name, format, content, commit_details) def write_page(name, format, content, commit_details)
request = Gitaly::WikiWritePageRequest.new( request = Gitaly::WikiWritePageRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
name: GitalyClient.encode(name), name: encode_binary(name),
format: format.to_s, format: format.to_s,
commit_details: gitaly_commit_details(commit_details) commit_details: gitaly_commit_details(commit_details)
) )
strio = GitalyClient.binary_stringio(content) strio = binary_stringio(content)
enum = Enumerator.new do |y| enum = Enumerator.new do |y|
until strio.eof? until strio.eof?
...@@ -39,13 +41,13 @@ module Gitlab ...@@ -39,13 +41,13 @@ module Gitlab
def update_page(page_path, title, format, content, commit_details) def update_page(page_path, title, format, content, commit_details)
request = Gitaly::WikiUpdatePageRequest.new( request = Gitaly::WikiUpdatePageRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
page_path: GitalyClient.encode(page_path), page_path: encode_binary(page_path),
title: GitalyClient.encode(title), title: encode_binary(title),
format: format.to_s, format: format.to_s,
commit_details: gitaly_commit_details(commit_details) commit_details: gitaly_commit_details(commit_details)
) )
strio = GitalyClient.binary_stringio(content) strio = binary_stringio(content)
enum = Enumerator.new do |y| enum = Enumerator.new do |y|
until strio.eof? until strio.eof?
...@@ -63,7 +65,7 @@ module Gitlab ...@@ -63,7 +65,7 @@ module Gitlab
def delete_page(page_path, commit_details) def delete_page(page_path, commit_details)
request = Gitaly::WikiDeletePageRequest.new( request = Gitaly::WikiDeletePageRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
page_path: GitalyClient.encode(page_path), page_path: encode_binary(page_path),
commit_details: gitaly_commit_details(commit_details) commit_details: gitaly_commit_details(commit_details)
) )
...@@ -73,9 +75,9 @@ module Gitlab ...@@ -73,9 +75,9 @@ module Gitlab
def find_page(title:, version: nil, dir: nil) def find_page(title:, version: nil, dir: nil)
request = Gitaly::WikiFindPageRequest.new( request = Gitaly::WikiFindPageRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
title: GitalyClient.encode(title), title: encode_binary(title),
revision: GitalyClient.encode(version), revision: encode_binary(version),
directory: GitalyClient.encode(dir) directory: encode_binary(dir)
) )
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_page, request) response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_page, request)
...@@ -102,8 +104,8 @@ module Gitlab ...@@ -102,8 +104,8 @@ module Gitlab
def find_file(name, revision) def find_file(name, revision)
request = Gitaly::WikiFindFileRequest.new( request = Gitaly::WikiFindFileRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
name: GitalyClient.encode(name), name: encode_binary(name),
revision: GitalyClient.encode(revision) revision: encode_binary(revision)
) )
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_file, request) response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_file, request)
...@@ -158,9 +160,9 @@ module Gitlab ...@@ -158,9 +160,9 @@ module Gitlab
def gitaly_commit_details(commit_details) def gitaly_commit_details(commit_details)
Gitaly::WikiCommitDetails.new( Gitaly::WikiCommitDetails.new(
name: GitalyClient.encode(commit_details.name), name: encode_binary(commit_details.name),
email: GitalyClient.encode(commit_details.email), email: encode_binary(commit_details.email),
message: GitalyClient.encode(commit_details.message) message: encode_binary(commit_details.message)
) )
end end
end end
......
...@@ -34,7 +34,7 @@ module Gitlab ...@@ -34,7 +34,7 @@ module Gitlab
private private
def pod_resource(command) def pod_resource(command)
Pod.new(command, @namespace.name, @kubeclient).generate Gitlab::Kubernetes::Helm::Pod.new(command, @namespace.name, @kubeclient).generate
end end
end end
end end
......
...@@ -5,7 +5,7 @@ module Gitlab ...@@ -5,7 +5,7 @@ module Gitlab
# Class for tracking timing information about method calls # Class for tracking timing information about method calls
class MethodCall class MethodCall
@@measurement_enabled_cache = Concurrent::AtomicBoolean.new(false) @@measurement_enabled_cache = Concurrent::AtomicBoolean.new(false)
@@measurement_enabled_cache_expires_at = Concurrent::AtomicFixnum.new(Time.now.to_i) @@measurement_enabled_cache_expires_at = Concurrent::AtomicReference.new(Time.now.to_i)
MUTEX = Mutex.new MUTEX = Mutex.new
BASE_LABELS = { module: nil, method: nil }.freeze BASE_LABELS = { module: nil, method: nil }.freeze
attr_reader :real_time, :cpu_time, :call_count, :labels attr_reader :real_time, :cpu_time, :call_count, :labels
......
...@@ -82,7 +82,10 @@ module Gitlab ...@@ -82,7 +82,10 @@ module Gitlab
end end
def issues def issues
issues = IssuesFinder.new(current_user).execute.where(project_id: project_ids_relation) issues = IssuesFinder.new(current_user).execute
unless default_project_filter
issues = issues.where(project_id: project_ids_relation)
end
issues = issues =
if query =~ /#(\d+)\z/ if query =~ /#(\d+)\z/
......
...@@ -57,11 +57,17 @@ module Gitlab ...@@ -57,11 +57,17 @@ module Gitlab
} }
end end
def highest_allowed_level def allowed_levels
restricted_levels = current_application_settings.restricted_visibility_levels restricted_levels = current_application_settings.restricted_visibility_levels
allowed_levels = self.values - restricted_levels self.values - restricted_levels
allowed_levels.max || PRIVATE end
def closest_allowed_level(target_level)
highest_allowed_level = allowed_levels.select { |level| level <= target_level }.max
# If all levels are restricted, fall back to PRIVATE
highest_allowed_level || PRIVATE
end end
def allowed_for?(user, level) def allowed_for?(user, level)
......
...@@ -2,10 +2,13 @@ module QA ...@@ -2,10 +2,13 @@ module QA
module Page module Page
module Menu module Menu
class Admin < Page::Base class Admin < Page::Base
<<<<<<< HEAD:qa/qa/page/menu/admin.rb
def go_to_geo_nodes def go_to_geo_nodes
click_link 'Geo Nodes' click_link 'Geo Nodes'
end end
=======
>>>>>>> upstream/master:qa/qa/page/menu/admin.rb
def go_to_license def go_to_license
click_link 'License' click_link 'License'
end end
......
...@@ -8,11 +8,13 @@ invalid_changelogs = Dir['changelogs/**/*'].reject do |changelog| ...@@ -8,11 +8,13 @@ invalid_changelogs = Dir['changelogs/**/*'].reject do |changelog|
begin begin
YAML.load_file(changelog) YAML.load_file(changelog)
rescue rescue => exception
puts exception
end end
end end
if invalid_changelogs.any? if invalid_changelogs.any?
puts
puts "Invalid changelogs found!\n" puts "Invalid changelogs found!\n"
puts invalid_changelogs.sort puts invalid_changelogs.sort
exit 1 exit 1
......
...@@ -3,12 +3,10 @@ ...@@ -3,12 +3,10 @@
require ::File.expand_path('../lib/gitlab/popen', __dir__) require ::File.expand_path('../lib/gitlab/popen', __dir__)
tasks = [ tasks = [
%w[bundle exec bundle-audit check --update],
%w[bundle exec rake config_lint], %w[bundle exec rake config_lint],
%w[bundle exec rake flay], %w[bundle exec rake flay],
%w[bundle exec rake haml_lint], %w[bundle exec rake haml_lint],
%w[bundle exec rake scss_lint], %w[bundle exec rake scss_lint],
%w[bundle exec rake brakeman],
%w[bundle exec license_finder], %w[bundle exec license_finder],
%w[yarn run eslint], %w[yarn run eslint],
%w[bundle exec rubocop --parallel], %w[bundle exec rubocop --parallel],
......
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