Commit 5331a49d authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'master' into fix/gb/improve-updating-column-in-batches-helper

* master: (56 commits)
  File view buttons
  Don't reset the session when the example failed, because we need capybara-screenshot to have access to it
  Resolve "MR comment + system note highlight don't have the same width"
  Add feature spec for dashboard state filter tabs
  Wording of Mysql support.
  a new feature checklist and more elaborate documentation requirements
  Filter archived project in API v3 only if param present
  Revert to using links instead of buttons in Issuable Index tabs.
  Do not run the codeclimate job on docs-only changes
  Only show gray footer space if environment actions exist
  Migrate Gitlab::Git::Blob.find to Gitaly
  Backport filtered search lazy token consistent state fix
  Add a comment explaining how the branch clean up happens
  Fix Github::Representation::PullRequest#source_branch_exists?
  Add CHANGELOG
  Fix GitHub importer performance on branch existence check
  Rebuild the dynamic path before validating it
  Rename stage ref migration specs to match a class name
  Enable Style/DotPosition Rubocop 👮
  Revert "Merge branch 'winh-merge-request-related-issues' into 'master'"
  ...

Conflicts:
	db/post_migrate/20170526185921_migrate_build_stage_reference.rb
parents 3a3dd539 270ca89d
......@@ -461,6 +461,7 @@ karma:
- coverage-javascript/
codeclimate:
<<: *except-docs
before_script: []
image: docker:latest
stage: test
......
......@@ -27,12 +27,24 @@ Please remove this notice if you're confident your issue isn't a duplicate.
### Documentation blurb
(Write the start of the documentation of this feature here, include:
#### Overview
1. Why should someone use it; what's the underlying problem.
2. What is the solution.
3. How does someone use this
What is it?
Why should someone use this feature?
What is the underlying (business) problem?
How do you use this feature?
During implementation, this can then be copied and used as a starter for the documentation.)
#### Use cases
/label ~"feature proposal"
Who is this for? Provide one or more use cases.
### Feature checklist
Make sure these are completed before closing the issue,
with a link to the relevant commit.
- [ ] [Feature assurance](https://about.gitlab.com/handbook/product/#feature-assurance)
- [ ] Documentation
- [ ] Added to [features.yml](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/features.yml)
/label ~"feature proposal"
\ No newline at end of file
......@@ -164,6 +164,11 @@ Style/DefWithParentheses:
Style/Documentation:
Enabled: false
# Multi-line method chaining should be done with leading dots.
Style/DotPosition:
Enabled: true
EnforcedStyle: leading
# This cop checks for uses of double negation (!!) to convert something
# to a boolean value. As this is both cryptic and usually redundant, it
# should be avoided.
......
......@@ -88,13 +88,6 @@ Security/YAMLLoad:
Style/BarePercentLiterals:
Enabled: false
# Offense count: 1403
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: leading, trailing
Style/DotPosition:
Enabled: false
# Offense count: 5
# Cop supports --auto-correct.
Style/EachWithObject:
......
......@@ -384,7 +384,7 @@ gem 'vmstat', '~> 2.3.0'
gem 'sys-filesystem', '~> 1.1.6'
# Gitaly GRPC client
gem 'gitaly', '~> 0.8.0'
gem 'gitaly', '~> 0.9.0'
gem 'toml-rb', '~> 0.3.15', require: false
......
......@@ -277,7 +277,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly (0.8.0)
gitaly (0.9.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
......@@ -977,7 +977,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly (~> 0.8.0)
gitaly (~> 0.9.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1)
......
......@@ -403,6 +403,14 @@ export default {
return '';
},
displayEnvironmentActions() {
return this.hasManualActions ||
this.externalURL ||
this.monitoringUrl ||
this.hasStopAction ||
this.canRetry;
},
/**
* Constructs folder URL based on the current location and the folder id.
*
......@@ -535,9 +543,12 @@ export default {
</span>
</div>
<div class="table-section section-30 table-button-footer" role="gridcell">
<div
v-if="!model.isFolder && displayEnvironmentActions"
class="table-section section-30 table-button-footer"
role="gridcell">
<div
v-if="!model.isFolder"
class="btn-group table-action-buttons"
role="group">
......
......@@ -487,6 +487,7 @@ class FilteredSearchManager {
}
searchState(e) {
e.preventDefault();
const target = e.currentTarget;
// remove focus outline after click
target.blur();
......
This diff is collapsed.
export default {
name: 'MRWidgetRelatedLinks',
props: {
isMerged: { type: Boolean, required: true },
relatedLinks: { type: Object, required: true },
},
computed: {
// TODO: the following should be handled by i18n
closingText() {
if (this.isMerged) {
return `Closed ${this.issueLabel('closing')}`;
}
return `Closes ${this.issueLabel('closing')}`;
},
hasLinks() {
const { closing, mentioned, assignToMe } = this.relatedLinks;
return closing || mentioned || assignToMe;
},
// TODO: the following should be handled by i18n
mentionedText() {
if (this.isMerged) {
if (this.hasMultipleIssues(this.relatedLinks.mentioned)) {
return 'are mentioned but were not closed';
}
return 'is mentioned but was not closed';
}
if (this.hasMultipleIssues(this.relatedLinks.mentioned)) {
return 'are mentioned but will not be closed';
}
return 'is mentioned but will not be closed';
},
},
methods: {
hasMultipleIssues(text) {
return /<\/a>,? and <a/.test(text);
return !text ? false : text.match(/<\/a> and <a/);
},
// TODO: the following should be handled by i18n
issueLabel(field) {
return this.hasMultipleIssues(this.relatedLinks[field]) ? 'issues' : 'issue';
},
verbLabel(field) {
return this.hasMultipleIssues(this.relatedLinks[field]) ? 'are' : 'is';
},
},
template: `
<div v-if="hasLinks">
<section
v-if="hasLinks"
class="mr-info-list mr-links">
<div class="legend"></div>
<p v-if="relatedLinks.closing">
{{closingText}}
Closes {{issueLabel('closing')}}
<span v-html="relatedLinks.closing"></span>.
</p>
<p v-if="relatedLinks.mentioned">
<span class="capitalize">{{issueLabel('mentioned')}}</span>
<span v-html="relatedLinks.mentioned"></span>
{{mentionedText}}
{{verbLabel('mentioned')}} mentioned but will not be closed.
</p>
<p v-if="relatedLinks.assignToMe">
<span v-html="relatedLinks.assignToMe"></span>
</p>
</div>
</section>
`,
};
/* global Flash */
import mrWidgetAuthorTime from '../../components/mr_widget_author_time';
import mrWidgetRelatedLinks from '../../components/mr_widget_related_links';
import eventHub from '../../event_hub';
import '../../../flash';
export default {
name: 'MRWidgetMerged',
......@@ -13,7 +11,6 @@ export default {
},
components: {
'mr-widget-author-and-time': mrWidgetAuthorTime,
'mr-widget-related-links': mrWidgetRelatedLinks,
},
data() {
return {
......@@ -21,9 +18,6 @@ export default {
};
},
computed: {
shouldRenderRelatedLinks() {
return this.mr.relatedLinks && this.mr.isMerged;
},
shouldShowRemoveSourceBranch() {
const { sourceBranchRemoved, isRemovingSourceBranch, canRemoveSourceBranch } = this.mr;
......@@ -92,10 +86,6 @@ export default {
aria-hidden="true" />
The source branch is being removed.
</p>
<mr-widget-related-links
v-if="shouldRenderRelatedLinks"
:is-merged="mr.isMerged()"
:related-links="mr.relatedLinks" />
</section>
<div
v-if="shouldShowMergedButtons"
......
......@@ -48,7 +48,7 @@ export default {
return stateMaps.stateToComponentMap[this.mr.state];
},
shouldRenderMergeHelp() {
return !this.mr.isMerged;
return stateMaps.statesToShowHelpWidget.indexOf(this.mr.state) > -1;
},
shouldRenderPipelines() {
return Object.keys(this.mr.pipeline).length || this.mr.hasCI;
......@@ -238,14 +238,9 @@ export default {
:is="componentName"
:mr="mr"
:service="service" />
<section
<mr-widget-related-links
v-if="shouldRenderRelatedLinks"
class="mr-info-list mr-links">
<div class="legend"></div>
<mr-widget-related-links
:is-merged="mr.isMerged"
:related-links="mr.relatedLinks" />
</section>
:related-links="mr.relatedLinks" />
<mr-widget-merge-help v-if="shouldRenderMergeHelp" />
</div>
`,
......
import Timeago from 'timeago.js';
import { getStateKey } from '../dependencies';
const unmergedStates = [
'locked',
'conflicts',
'workInProgress',
'readyToMerge',
'checking',
'unresolvedDiscussions',
'pipelineFailed',
'pipelineBlocked',
'autoMergeFailed',
];
export default class MergeRequestStore {
constructor(data) {
......@@ -77,7 +65,6 @@ export default class MergeRequestStore {
this.mergeActionsContentPath = data.commit_change_content_path;
this.isRemovingSourceBranch = this.isRemovingSourceBranch || false;
this.isOpen = data.state === 'opened' || data.state === 'reopened' || false;
this.isMerged = unmergedStates.indexOf(data.state) === -1;
this.hasMergeableDiscussionsState = data.mergeable_discussions_state === false;
this.canRemoveSourceBranch = currentUser.can_remove_source_branch || false;
this.canMerge = !!data.merge_path;
......
......@@ -19,6 +19,19 @@ const stateToComponentMap = {
shaMismatch: 'mr-widget-sha-mismatch',
};
const statesToShowHelpWidget = [
'locked',
'conflicts',
'workInProgress',
'readyToMerge',
'checking',
'unresolvedDiscussions',
'pipelineFailed',
'pipelineBlocked',
'autoMergeFailed',
];
export default {
stateToComponentMap,
statesToShowHelpWidget,
};
......@@ -45,8 +45,7 @@
li {
display: flex;
a,
.btn-link {
a {
padding: $gl-btn-padding;
padding-bottom: 11px;
font-size: 14px;
......@@ -68,29 +67,7 @@
}
}
.btn-link {
padding-top: 16px;
padding-left: 15px;
padding-right: 15px;
border-left: none;
border-right: none;
border-top: none;
border-radius: 0;
&:hover,
&:active,
&:focus {
background-color: transparent;
}
&:active {
outline: 0;
box-shadow: none;
}
}
&.active a,
&.active .btn-link {
&.active a {
border-bottom: 2px solid $link-underline-blue;
color: $black;
font-weight: 600;
......
......@@ -44,6 +44,10 @@
&:target,
&.target {
background: $line-target-blue;
&.system-note .note-body .note-text.system-note-commit-list::after {
background: linear-gradient(rgba($line-target-blue, 0.1) -100px, $line-target-blue 100%);
}
}
.avatar {
......
......@@ -323,6 +323,7 @@ $note-disabled-comment-color: #b2b2b2;
$note-targe3-outside: #fffff0;
$note-targe3-inside: #ffffd3;
$note-line2-border: #ddd;
$note-icon-gutter-width: 55px;
/*
......
......@@ -372,10 +372,6 @@
margin-left: 12px;
}
&.mr-state-locked + .mr-info-list.mr-links {
margin-top: -16px;
}
&.empty-state {
.artwork {
margin-bottom: $gl-padding;
......
......@@ -148,8 +148,20 @@
padding: 6px 0;
}
.notes-form > li {
border: 0;
.notes.notes-form > li.timeline-entry {
@include notes-media('max', $screen-sm-max) {
padding: 0;
}
.timeline-content {
@include notes-media('max', $screen-sm-max) {
margin: 0;
}
}
.timeline-entry-inner {
border: 0;
}
}
.note-edit-form {
......
......@@ -14,16 +14,6 @@ ul.notes {
margin: 0;
padding: 0;
.timeline-content {
margin-left: 55px;
&.timeline-content-form {
@include notes-media('max', $screen-sm-max) {
margin-left: 0;
}
}
}
.note-created-ago,
.note-updated-at {
white-space: nowrap;
......@@ -46,17 +36,49 @@ ul.notes {
}
}
> li {
padding: $gl-padding $gl-btn-padding;
> li { // .timeline-entry
padding: 0;
display: block;
position: relative;
border-bottom: 1px solid $white-normal;
border-bottom: 0;
@include notes-media('min', $screen-sm-min) {
padding-left: $note-icon-gutter-width;
}
&:last-child {
// Override `.timeline > li:last-child { border-bottom: none; }`
.timeline-entry-inner {
padding: $gl-padding $gl-btn-padding;
border-bottom: 1px solid $white-normal;
}
&:target,
&.target {
border-bottom: 1px solid $white-normal;
&:not(:first-child) {
border-top: 1px solid $white-normal;
margin-top: -1px;
}
.timeline-entry-inner {
border-bottom: 0;
}
}
.timeline-icon {
@include notes-media('min', $screen-sm-min) {
margin-left: -$note-icon-gutter-width;
}
}
.timeline-content {
margin-left: $note-icon-gutter-width;
@include notes-media('min', $screen-sm-min) {
margin-left: 0;
}
}
&.being-posted {
pointer-events: none;
opacity: 0.5;
......@@ -73,7 +95,7 @@ ul.notes {
}
&.note-discussion {
&.timeline-entry {
.timeline-entry-inner {
padding: $gl-padding 10px;
}
}
......@@ -152,13 +174,8 @@ ul.notes {
.system-note {
font-size: 14px;
padding-left: 0;
clear: both;
@include notes-media('min', $screen-sm-min) {
margin-left: 65px;
}
.note-header-info {
padding-bottom: 0;
}
......@@ -192,13 +209,16 @@ ul.notes {
.timeline-icon {
float: left;
@include notes-media('min', $screen-sm-min) {
margin-left: 0;
width: auto;
}
svg {
width: 16px;
height: 16px;
fill: $gray-darkest;
position: absolute;
left: 0;
top: 2px;
margin-top: 2px;
}
}
......@@ -250,7 +270,7 @@ ul.notes {
&::after {
content: '';
width: 100%;
height: 67px;
height: 70px;
position: absolute;
left: 0;
bottom: 0;
......@@ -639,15 +659,12 @@ ul.notes {
.discussion-body,
.diff-file {
.notes .note {
padding-left: $gl-padding;
padding-right: $gl-padding;
&.system-note {
padding-left: 0;
border-bottom: 1px solid $white-normal;
@media (min-width: $screen-sm-min) {
margin-left: 70px;
}
.timeline-entry-inner {
padding-left: $gl-padding;
padding-right: $gl-padding;
border-bottom: none;
}
}
}
......
......@@ -380,7 +380,7 @@ a.deploy-project-label {
padding: 0;
background: transparent;
border: none;
line-height: 36px;
line-height: 34px;
margin: 0;
> li + li::before {
......
.tree-holder {
> .nav-block {
margin: 11px 0;
.nav-block {
margin: 10px 0;
@media (min-width: $screen-sm-min) {
display: flex;
.tree-ref-container {
flex: 1;
}
.tree-controls {
text-align: right;
.btn-group {
margin-left: 10px;
}
}
.tree-ref-holder {
float: left;
margin-right: 15px;
}
.repo-breadcrumb {
li:last-of-type {
position: relative;
}
}
.add-to-tree-dropdown {
position: absolute;
left: 18px;
}
}
}
@media (max-width: $screen-xs-max) {
.repo-breadcrumb {
margin-top: 10px;
position: relative;
.dropdown-menu {
min-width: 100%;
width: 100%;
left: inherit;
right: 0;
}
}
.add-to-tree-dropdown {
position: absolute;
left: 0;
right: 0;
}
.tree-controls {
margin-bottom: 10px;
.btn,
.dropdown,
.btn-group {
width: 100%;
}
.btn {
margin: 10px 0 0;
}
}
}
.file-finder {
......@@ -131,11 +197,6 @@
}
}
.tree-ref-holder {
float: left;
margin-right: 15px;
}
.blob-commit-info {
list-style: none;
margin: 0;
......@@ -159,16 +220,6 @@
color: $md-link-color;
}
.tree-controls {
float: right;
position: relative;
z-index: 2;
.project-action-button {
margin-left: $btn-side-margin;
}
}
.repo-charts {
.sub-header {
margin: 20px 0;
......
......@@ -97,8 +97,8 @@ module CreatesCommit
def merge_request_exists?
return @merge_request if defined?(@merge_request)
@merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.
find_by(source_project_id: @project_to_commit_into, source_branch: @branch_name, target_branch: @start_branch)
@merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened
.find_by(source_project_id: @project_to_commit_into, source_branch: @branch_name, target_branch: @start_branch)
end
def different_project?
......
......@@ -15,8 +15,8 @@ module MembershipActions
end
def destroy
Members::DestroyService.new(membershipable, current_user, params).
execute(:all)
Members::DestroyService.new(membershipable, current_user, params)
.execute(:all)
respond_to do |format|
format.html do
......@@ -42,8 +42,8 @@ module MembershipActions
end
def leave
member = Members::DestroyService.new(membershipable, current_user, user_id: current_user.id).
execute(:all)
member = Members::DestroyService.new(membershipable, current_user, user_id: current_user.id)
.execute(:all)
notice =
if member.request?
......
......@@ -22,8 +22,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def starred
@projects = load_projects(params.merge(starred: true)).
includes(:forked_from_project, :tags).page(params[:page])
@projects = load_projects(params.merge(starred: true))
.includes(:forked_from_project, :tags).page(params[:page])
@groups = []
......@@ -45,8 +45,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def load_projects(finder_params)
ProjectsFinder.new(params: finder_params, current_user: current_user).
execute.includes(:route, namespace: :route)
ProjectsFinder.new(params: finder_params, current_user: current_user)
.execute.includes(:route, namespace: :route)
end
def load_events
......
......@@ -49,7 +49,7 @@ class Explore::ProjectsController < Explore::ApplicationController
private
def load_projects
ProjectsFinder.new(current_user: current_user, params: params).
execute.includes(:route, namespace: :route)
ProjectsFinder.new(current_user: current_user, params: params)
.execute.includes(:route, namespace: :route)
end
end
......@@ -11,8 +11,8 @@ class JwtController < ApplicationController
service = SERVICES[params[:service]]
return head :not_found unless service
result = service.new(@authentication_result.project, @authentication_result.actor, auth_params).
execute(authentication_abilities: @authentication_result.authentication_abilities)
result = service.new(@authentication_result.project, @authentication_result.actor, auth_params)
.execute(authentication_abilities: @authentication_result.authentication_abilities)
render json: result, status: result[:http_status]
end
......
......@@ -144,7 +144,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
def log_audit_event(user, options = {})
AuditEventService.new(user, user, options).
for_authentication.security_event
AuditEventService.new(user, user, options)
.for_authentication.security_event
end
end
......@@ -49,9 +49,9 @@ class ProfilesController < Profiles::ApplicationController
end
def audit_log
@events = AuditEvent.where(entity_type: "User", entity_id: current_user.id).
order("created_at DESC").
page(params[:page])
@events = AuditEvent.where(entity_type: "User", entity_id: current_user.id)
.order("created_at DESC")
.page(params[:page])
end
def update_username
......
......@@ -53,9 +53,21 @@ class Projects::ApplicationController < ApplicationController
end
end
def check_project_feature_available!(feature)
render_404 unless project.feature_available?(feature, current_user)
end
def check_issuables_available!
render_404 unless project.feature_available?(:issues, current_user) ||
project.feature_available?(:merge_requests, current_user)
end
def method_missing(method_sym, *arguments, &block)
if method_sym.to_s =~ /\Aauthorize_(.*)!\z/
case method_sym.to_s
when /\Aauthorize_(.*)!\z/
authorize_action!($1.to_sym)
when /\Acheck_(.*)_available!\z/
check_project_feature_available!($1.to_sym)
else
super
end
......
......@@ -187,7 +187,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def set_last_commit_sha
@last_commit_sha = Gitlab::Git::Commit.
last_for_path(@repository, @ref, @path).sha
@last_commit_sha = Gitlab::Git::Commit
.last_for_path(@repository, @ref, @path).sha
end
end
......@@ -37,8 +37,8 @@ class Projects::BranchesController < Projects::ApplicationController
redirect_to_autodeploy = project.empty_repo? && project.deployment_services.present?
result = CreateBranchService.new(project, current_user).
execute(branch_name, ref)
result = CreateBranchService.new(project, current_user)
.execute(branch_name, ref)
if params[:issue_iid]
issue = IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:issue_iid])
......
......@@ -18,11 +18,11 @@ class Projects::CommitsController < Projects::ApplicationController
@repository.commits(@ref, path: @path, limit: @limit, offset: @offset)
end
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
@note_counts = project.notes.where(commit_id: @commits.map(&:id))
.group(:commit_id).count
@merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.
find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref)
@merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened
.find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref)
respond_to do |format|
format.html
......
......@@ -61,7 +61,7 @@ class Projects::CompareController < Projects::ApplicationController
end
def merge_request
@merge_request ||= MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.
find_by(source_project: @project, source_branch: @head_ref, target_branch: @start_ref)
@merge_request ||= MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened
.find_by(source_project: @project, source_branch: @head_ref, target_branch: @start_ref)
end
end
class Projects::DiscussionsController < Projects::ApplicationController
before_action :module_enabled
before_action :check_merge_requests_available!
before_action :merge_request
before_action :discussion
before_action :authorize_resolve_discussion!
......@@ -34,8 +34,4 @@ class Projects::DiscussionsController < Projects::ApplicationController
def authorize_resolve_discussion!
access_denied! unless discussion.can_resolve?(current_user)
end
def module_enabled
render_404 unless @project.feature_available?(:merge_requests, current_user)
end
end
......@@ -15,8 +15,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController
respond_to do |format|
format.html
format.json do
Gitlab::PollingInterval.set_header(response, interval: 3_000)
render json: {
environments: EnvironmentSerializer
.new(project: @project, current_user: @current_user)
......
......@@ -9,7 +9,7 @@ class Projects::IssuesController < Projects::ApplicationController
prepend_before_action :authenticate_user!, only: [:new]
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled
before_action :check_issues_available!
before_action :issue, except: [:index, :new, :create, :bulk_update]
# Allow write(create) issue
......@@ -250,7 +250,7 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user)
end
def module_enabled
def check_issues_available!
return render_404 unless @project.feature_available?(:issues, current_user) && @project.default_issues_tracker?
end
......
class Projects::LabelsController < Projects::ApplicationController
include ToggleSubscriptionAction
before_action :module_enabled
before_action :check_issuables_available!
before_action :label, only: [:edit, :update, :destroy, :promote]
before_action :find_labels, only: [:index, :set_priorities, :remove_priority, :toggle_subscription]
before_action :authorize_read_label!
......@@ -135,12 +135,6 @@ class Projects::LabelsController < Projects::ApplicationController
protected
def module_enabled
unless @project.feature_available?(:issues, current_user) || @project.feature_available?(:merge_requests, current_user)
return render_404
end
end
def label_params
params.require(:label).permit(:title, :description, :color)
end
......
......@@ -7,7 +7,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include ToggleAwardEmoji
include IssuableCollections
before_action :module_enabled
before_action :check_merge_requests_available!
before_action :merge_request, only: [
:edit, :update, :show, :diffs, :commits, :conflicts, :conflict_for_path, :pipelines, :merge,
:pipeline_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_pipeline_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues, :commit_change_content
......@@ -143,8 +143,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
@note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
@note_counts = Note.where(commit_id: @commits.map(&:id))
.group(:commit_id).count
render json: { html: view_to_html_string('projects/merge_requests/show/_commits') }
end
......@@ -192,9 +192,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
begin
MergeRequests::Conflicts::ResolveService.
new(merge_request).
execute(current_user, params)
MergeRequests::Conflicts::ResolveService
.new(merge_request)
.execute(current_user, params)
flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
......@@ -461,10 +461,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return render_404 unless @conflicts_list.can_be_resolved_by?(current_user)
end
def module_enabled
return render_404 unless @project.feature_available?(:merge_requests, current_user)
end
def validates_merge_request
# Show git not found page
# if there is no saved commits between source & target branch
......@@ -562,8 +558,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@commits = @merge_request.compare_commits.reverse
@commit = @merge_request.diff_head_commit
@note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
@note_counts = Note.where(commit_id: @commits.map(&:id))
.group(:commit_id).count
@labels = LabelsFinder.new(current_user, project_id: @project.id).execute
......
class Projects::MilestonesController < Projects::ApplicationController
include MilestoneActions
before_action :module_enabled
before_action :check_issuables_available!
before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels]
# Allow read any milestone
......@@ -95,12 +95,6 @@ class Projects::MilestonesController < Projects::ApplicationController
return render_404 unless can?(current_user, :admin_milestone, @project)
end
def module_enabled
unless @project.feature_available?(:issues, current_user) || @project.feature_available?(:merge_requests, current_user)
return render_404
end
end
def milestone_params
params.require(:milestone).permit(:title, :description, :start_date, :due_date, :state_event)
end
......
......@@ -14,8 +14,8 @@ module Projects
def define_runners_variables
@project_runners = @project.runners.ordered
@assignable_runners = current_user.ci_authorized_runners.
assignable_for(project).ordered.page(params[:page]).per(20)
@assignable_runners = current_user.ci_authorized_runners
.assignable_for(project).ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
end
......
......@@ -5,7 +5,7 @@ class Projects::SnippetsController < Projects::ApplicationController
include SnippetsActions
include RendersBlob
before_action :module_enabled
before_action :check_snippets_available!
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
# Allow read any snippet
......@@ -102,10 +102,6 @@ class Projects::SnippetsController < Projects::ApplicationController
return render_404 unless can?(current_user, :admin_project_snippet, @snippet)
end
def module_enabled
return render_404 unless @project.feature_available?(:snippets, current_user)
end
def snippet_params
params.require(:project_snippet).permit(:title, :content, :file_name, :private, :visibility_level, :description)
end
......
......@@ -29,8 +29,8 @@ class Projects::TagsController < Projects::ApplicationController
end
def create
result = Tags::CreateService.new(@project, current_user).
execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
result = Tags::CreateService.new(@project, current_user)
.execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
if result[:status] == :success
@tag = result[:tag]
......
......@@ -128,8 +128,8 @@ class SessionsController < Devise::SessionsController
end
def log_audit_event(user, options = {})
AuditEventService.new(user, user, options).
for_authentication.security_event
AuditEventService.new(user, user, options)
.for_authentication.security_event
end
def log_user_activity(user)
......
......@@ -4,8 +4,8 @@ module Sherlock
def find_transaction
if params[:transaction_id]
@transaction = Gitlab::Sherlock.collection.
find_transaction(params[:transaction_id])
@transaction = Gitlab::Sherlock.collection
.find_transaction(params[:transaction_id])
end
end
end
......
......@@ -106,11 +106,11 @@ class UsersController < ApplicationController
def load_events
# Get user activity feed for projects common for both users
@events = user.recent_events.
merge(projects_for_current_user).
references(:project).
with_associations.
limit_recent(20, params[:offset])
@events = user.recent_events
.merge(projects_for_current_user)
.references(:project)
.with_associations
.limit_recent(20, params[:offset])
end
def load_projects
......
......@@ -33,8 +33,8 @@ class EventsFinder
private
def by_current_user_access(events)
events.merge(ProjectsFinder.new(current_user: current_user).execute).
joins(:project)
events.merge(ProjectsFinder.new(current_user: current_user).execute)
.joins(:project)
end
def by_action(events)
......
......@@ -8,9 +8,9 @@ class GroupMembersFinder
return group_members unless @group.parent
parents_members = GroupMember.non_request.
where(source_id: @group.ancestors.select(:id)).
where.not(user_id: @group.users.select(:id))
parents_members = GroupMember.non_request
.where(source_id: @group.ancestors.select(:id))
.where.not(user_id: @group.users.select(:id))
wheres = ["members.id IN (#{group_members.select(:id).to_sql})"]
wheres << "members.id IN (#{parents_members.select(:id).to_sql})"
......
......@@ -8,10 +8,10 @@ module FormHelper
content_tag(:div, class: 'alert alert-danger', id: 'error_explanation') do
content_tag(:h4, headline) <<
content_tag(:ul) do
model.errors.full_messages.
map { |msg| content_tag(:li, msg) }.
join.
html_safe
model.errors.full_messages
.map { |msg| content_tag(:li, msg) }
.join
.html_safe
end
end
end
......
......@@ -194,8 +194,8 @@ module ProjectsHelper
end
def load_pipeline_status(projects)
Gitlab::Cache::Ci::ProjectPipelineStatus.
load_in_batch_for_projects(projects)
Gitlab::Cache::Ci::ProjectPipelineStatus
.load_in_batch_for_projects(projects)
end
private
......
......@@ -97,8 +97,8 @@ module SearchHelper
# Autocomplete results for the current user's projects
def projects_autocomplete(term, limit = 5)
current_user.authorized_projects.search_by_title(term).
sorted_by_stars.non_archived.limit(limit).map do |p|
current_user.authorized_projects.search_by_title(term)
.sorted_by_stars.non_archived.limit(limit).map do |p|
{
category: "Projects",
id: p.id,
......
......@@ -6,8 +6,8 @@ module WikiHelper
# Returns a String composed of the capitalized name of each directory and the
# capitalized name of the page itself.
def breadcrumb(page_slug)
page_slug.split('/').
map { |dir_or_page| WikiPage.unhyphenize(dir_or_page).capitalize }.
join(' / ')
page_slug.split('/')
.map { |dir_or_page| WikiPage.unhyphenize(dir_or_page).capitalize }
.join(' / ')
end
end
......@@ -19,9 +19,9 @@ class AwardEmoji < ActiveRecord::Base
class << self
def votes_for_collection(ids, type)
select('name', 'awardable_id', 'COUNT(*) as count').
where('name IN (?) AND awardable_type = ? AND awardable_id IN (?)', [DOWNVOTE_NAME, UPVOTE_NAME], type, ids).
group('name', 'awardable_id')
select('name', 'awardable_id', 'COUNT(*) as count')
.where('name IN (?) AND awardable_type = ? AND awardable_id IN (?)', [DOWNVOTE_NAME, UPVOTE_NAME], type, ids)
.group('name', 'awardable_id')
end
end
......
......@@ -138,17 +138,6 @@ module Ci
ExpandVariables.expand(environment, simple_variables) if environment
end
def environment_url
return @environment_url if defined?(@environment_url)
@environment_url =
if unexpanded_url = options&.dig(:environment, :url)
ExpandVariables.expand(unexpanded_url, simple_variables)
else
persisted_environment&.external_url
end
end
def has_environment?
environment.present?
end
......@@ -192,7 +181,7 @@ module Ci
slugified.gsub(/[^a-z0-9]/, '-')[0..62]
end
# Variables whose value does not depend on other variables
# Variables whose value does not depend on environment
def simple_variables
variables = predefined_variables
variables += project.predefined_variables
......@@ -207,7 +196,8 @@ module Ci
variables
end
# All variables, including those dependent on other variables
# All variables, including those dependent on environment, which could
# contain unexpanded variables.
def variables
simple_variables.concat(persisted_environment_variables)
end
......@@ -481,9 +471,10 @@ module Ci
variables = persisted_environment.predefined_variables
if url = environment_url
variables << { key: 'CI_ENVIRONMENT_URL', value: url, public: true }
end
# Here we're passing unexpanded environment_url for runner to expand,
# and we need to make sure that CI_ENVIRONMENT_NAME and
# CI_ENVIRONMENT_SLUG so on are available for the URL be expanded.
variables << { key: 'CI_ENVIRONMENT_URL', value: environment_url, public: true } if environment_url
variables
end
......@@ -506,6 +497,10 @@ module Ci
variables
end
def environment_url
options&.dig(:environment, :url) || persisted_environment&.external_url
end
def build_attributes_from_config
return {} unless pipeline.config_processor
......
......@@ -168,8 +168,8 @@ module Ci
end
def stages_names
statuses.order(:stage_idx).distinct.
pluck(:stage, :stage_idx).map(&:first)
statuses.order(:stage_idx).distinct
.pluck(:stage, :stage_idx).map(&:first)
end
def legacy_stage(name)
......
......@@ -30,8 +30,8 @@ module Ci
scope :assignable_for, ->(project) do
# FIXME: That `to_sql` is needed to workaround a weird Rails bug.
# Without that, placeholders would miss one and couldn't match.
where(locked: false).
where.not("id IN (#{project.runners.select(:id).to_sql})").specific
where(locked: false)
.where.not("id IN (#{project.runners.select(:id).to_sql})").specific
end
validate :tag_constraints
......
......@@ -161,9 +161,9 @@ module Issuable
#
milestones_due_date = 'MIN(milestones.due_date)'
order_milestone_due_asc.
order_labels_priority(excluded_labels: excluded_labels, extra_select_columns: [milestones_due_date]).
reorder(Gitlab::Database.nulls_last_order(milestones_due_date, 'ASC'),
order_milestone_due_asc
.order_labels_priority(excluded_labels: excluded_labels, extra_select_columns: [milestones_due_date])
.reorder(Gitlab::Database.nulls_last_order(milestones_due_date, 'ASC'),
Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
end
......@@ -182,9 +182,9 @@ module Issuable
"(#{highest_priority}) AS highest_priority"
] + extra_select_columns
select(select_columns.join(', ')).
group(arel_table[:id]).
reorder(Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
select(select_columns.join(', '))
.group(arel_table[:id])
.reorder(Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
end
def with_label(title, sort = nil)
......
......@@ -18,10 +18,10 @@ module RelativePositioning
prev_pos = nil
if self.relative_position
prev_pos = self.class.
in_projects(project.id).
where('relative_position < ?', self.relative_position).
maximum(:relative_position)
prev_pos = self.class
.in_projects(project.id)
.where('relative_position < ?', self.relative_position)
.maximum(:relative_position)
end
prev_pos
......@@ -31,10 +31,10 @@ module RelativePositioning
next_pos = nil
if self.relative_position
next_pos = self.class.
in_projects(project.id).
where('relative_position > ?', self.relative_position).
minimum(:relative_position)
next_pos = self.class
.in_projects(project.id)
.where('relative_position > ?', self.relative_position)
.minimum(:relative_position)
end
next_pos
......
......@@ -107,6 +107,14 @@ module Routable
RequestStore[key] ||= uncached_full_path
end
def build_full_path
if parent && path
parent.full_path + '/' + path
else
path
end
end
private
def uncached_full_path
......@@ -135,14 +143,6 @@ module Routable
end
end
def build_full_path
if parent && path
parent.full_path + '/' + path
else
path
end
end
def update_route
prepare_route
route.save
......
......@@ -39,12 +39,12 @@ module Sortable
private
def highest_label_priority(target_type_column: nil, target_type: nil, target_column:, project_column:, excluded_labels: [])
query = Label.select(LabelPriority.arel_table[:priority].minimum).
left_join_priorities.
joins(:label_links).
where("label_priorities.project_id = #{project_column}").
where("label_links.target_id = #{target_column}").
reorder(nil)
query = Label.select(LabelPriority.arel_table[:priority].minimum)
.left_join_priorities
.joins(:label_links)
.where("label_priorities.project_id = #{project_column}")
.where("label_links.target_id = #{target_column}")
.reorder(nil)
query =
if target_type_column
......
......@@ -27,16 +27,16 @@ module Subscribable
end
def subscribers(project)
subscriptions_available(project).
where(subscribed: true).
map(&:user)
subscriptions_available(project)
.where(subscribed: true)
.map(&:user)
end
def toggle_subscription(user, project = nil)
unsubscribe_from_other_levels(user, project)
find_or_initialize_subscription(user, project).
update(subscribed: !subscribed?(user, project))
find_or_initialize_subscription(user, project)
.update(subscribed: !subscribed?(user, project))
end
def subscribe(user, project = nil)
......@@ -69,14 +69,14 @@ module Subscribable
end
def find_or_initialize_subscription(user, project)
subscriptions.
find_or_initialize_by(user_id: user.id, project_id: project.try(:id))
subscriptions
.find_or_initialize_by(user_id: user.id, project_id: project.try(:id))
end
def subscriptions_available(project)
t = Subscription.arel_table
subscriptions.
where(t[:project_id].eq(nil).or(t[:project_id].eq(project.try(:id))))
subscriptions
.where(t[:project_id].eq(nil).or(t[:project_id].eq(project.try(:id))))
end
end
......@@ -58,10 +58,10 @@ class Deployment < ActiveRecord::Base
def update_merge_request_metrics!
return unless environment.update_merge_request_metrics?
merge_requests = project.merge_requests.
joins(:metrics).
where(target_branch: self.ref, merge_request_metrics: { first_deployed_to_production_at: nil }).
where("merge_request_metrics.merged_at <= ?", self.created_at)
merge_requests = project.merge_requests
.joins(:metrics)
.where(target_branch: self.ref, merge_request_metrics: { first_deployed_to_production_at: nil })
.where("merge_request_metrics.merged_at <= ?", self.created_at)
if previous_deployment
merge_requests = merge_requests.where("merge_request_metrics.merged_at >= ?", previous_deployment.created_at)
......@@ -76,17 +76,17 @@ class Deployment < ActiveRecord::Base
merge_requests.map(&:id)
end
MergeRequest::Metrics.
where(merge_request_id: merge_request_ids, first_deployed_to_production_at: nil).
update_all(first_deployed_to_production_at: self.created_at)
MergeRequest::Metrics
.where(merge_request_id: merge_request_ids, first_deployed_to_production_at: nil)
.update_all(first_deployed_to_production_at: self.created_at)
end
def previous_deployment
@previous_deployment ||=
project.deployments.joins(:environment).
where(environments: { name: self.environment.name }, ref: self.ref).
where.not(id: self.id).
take
project.deployments.joins(:environment)
.where(environments: { name: self.environment.name }, ref: self.ref)
.where.not(id: self.id)
.take
end
def stop_action
......
......@@ -40,9 +40,9 @@ class Environment < ActiveRecord::Base
scope :stopped, -> { with_state(:stopped) }
scope :order_by_last_deployed_at, -> do
max_deployment_id_sql =
Deployment.select(Deployment.arel_table[:id].maximum).
where(Deployment.arel_table[:environment_id].eq(arel_table[:id])).
to_sql
Deployment.select(Deployment.arel_table[:id].maximum)
.where(Deployment.arel_table[:environment_id].eq(arel_table[:id]))
.to_sql
order(Gitlab::Database.nulls_first_order("(#{max_deployment_id_sql})", 'ASC'))
end
......
......@@ -376,9 +376,9 @@ class Event < ActiveRecord::Base
# At this point it's possible for multiple threads/processes to try to
# update the project. Only one query should actually perform the update,
# hence we add the extra WHERE clause for last_activity_at.
Project.unscoped.where(id: project_id).
where('last_activity_at <= ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago).
update_all(last_activity_at: created_at)
Project.unscoped.where(id: project_id)
.where('last_activity_at <= ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago)
.update_all(last_activity_at: created_at)
end
def authored_by?(user)
......@@ -392,7 +392,7 @@ class Event < ActiveRecord::Base
end
def set_last_repository_updated_at
Project.unscoped.where(id: project_id).
update_all(last_repository_updated_at: created_at)
Project.unscoped.where(id: project_id)
.update_all(last_repository_updated_at: created_at)
end
end
......@@ -206,8 +206,8 @@ class Group < Namespace
end
def refresh_members_authorized_projects
UserProjectAccessChangedService.new(user_ids_for_project_authorizations).
execute
UserProjectAccessChangedService.new(user_ids_for_project_authorizations)
.execute
end
def user_ids_for_project_authorizations
......@@ -225,10 +225,10 @@ class Group < Namespace
def max_member_access_for_user(user)
return GroupMember::OWNER if user.admin?
members_with_parents.
where(user_id: user).
reorder(access_level: :desc).
first&.
members_with_parents
.where(user_id: user)
.reorder(access_level: :desc)
.first&.
access_level || GroupMember::NO_ACCESS
end
......
......@@ -124,8 +124,8 @@ class Issue < ActiveRecord::Base
end
def self.order_by_position_and_priority
order_labels_priority.
reorder(Gitlab::Database.nulls_last_order('relative_position', 'ASC'),
order_labels_priority
.reorder(Gitlab::Database.nulls_last_order('relative_position', 'ASC'),
Gitlab::Database.nulls_last_order('highest_priority', 'ASC'),
"id DESC")
end
......
......@@ -17,9 +17,9 @@ class IssueCollection
# Given all the issue projects we get a list of projects that the current
# user has at least reporter access to.
projects_with_reporter_access = user.
projects_with_reporter_access_limited_to(project_ids).
pluck(:id)
projects_with_reporter_access = user
.projects_with_reporter_access_limited_to(project_ids)
.pluck(:id)
collection.select do |issue|
if projects_with_reporter_access.include?(issue.project_id)
......
......@@ -46,9 +46,9 @@ class Label < ActiveRecord::Base
labels = Label.arel_table
priorities = LabelPriority.arel_table
label_priorities = labels.join(priorities, Arel::Nodes::OuterJoin).
on(labels[:id].eq(priorities[:label_id]).and(priorities[:project_id].eq(project.id))).
join_sources
label_priorities = labels.join(priorities, Arel::Nodes::OuterJoin)
.on(labels[:id].eq(priorities[:label_id]).and(priorities[:project_id].eq(project.id)))
.join_sources
joins(label_priorities).where(priorities[:priority].eq(nil))
end
......@@ -57,9 +57,9 @@ class Label < ActiveRecord::Base
labels = Label.arel_table
priorities = LabelPriority.arel_table
label_priorities = labels.join(priorities, Arel::Nodes::OuterJoin).
on(labels[:id].eq(priorities[:label_id])).
join_sources
label_priorities = labels.join(priorities, Arel::Nodes::OuterJoin)
.on(labels[:id].eq(priorities[:label_id]))
.join_sources
joins(label_priorities)
end
......
......@@ -99,9 +99,9 @@ class Member < ActiveRecord::Base
users = User.arel_table
members = Member.arel_table
member_users = members.join(users, Arel::Nodes::OuterJoin).
on(members[:user_id].eq(users[:id])).
join_sources
member_users = members.join(users, Arel::Nodes::OuterJoin)
.on(members[:user_id].eq(users[:id]))
.join_sources
joins(member_users)
end
......
......@@ -577,8 +577,8 @@ class MergeRequest < ActiveRecord::Base
messages = [title, description]
messages.concat(commits.map(&:safe_message)) if merge_request_diff
Gitlab::ClosingIssueExtractor.new(project, current_user).
closed_by_message(messages.join("\n"))
Gitlab::ClosingIssueExtractor.new(project, current_user)
.closed_by_message(messages.join("\n"))
else
[]
end
......
......@@ -7,9 +7,9 @@ class MergeRequestsClosingIssues < ActiveRecord::Base
class << self
def count_for_collection(ids)
group(:issue_id).
where(issue_id: ids).
pluck('issue_id', 'COUNT(*) as count')
group(:issue_id)
.where(issue_id: ids)
.pluck('issue_id', 'COUNT(*) as count')
end
end
end
......@@ -98,11 +98,11 @@ class Milestone < ActiveRecord::Base
if Gitlab::Database.postgresql?
rel.order(:project_id, :due_date).select('DISTINCT ON (project_id) id')
else
rel.
group(:project_id).
having('due_date = MIN(due_date)').
pluck(:id, :project_id, :due_date).
map(&:first)
rel
.group(:project_id)
.having('due_date = MIN(due_date)')
.pluck(:id, :project_id, :due_date)
.map(&:first)
end
end
......
......@@ -181,16 +181,16 @@ class Namespace < ActiveRecord::Base
def ancestors
return self.class.none unless parent_id
Gitlab::GroupHierarchy.
new(self.class.where(id: parent_id)).
base_and_ancestors
Gitlab::GroupHierarchy
.new(self.class.where(id: parent_id))
.base_and_ancestors
end
# Returns all the descendants of the current namespace.
def descendants
Gitlab::GroupHierarchy.
new(self.class.where(parent_id: id)).
base_and_descendants
Gitlab::GroupHierarchy
.new(self.class.where(parent_id: id))
.base_and_descendants
end
def user_ids_for_project_authorizations
......@@ -253,10 +253,10 @@ class Namespace < ActiveRecord::Base
end
def refresh_access_of_projects_invited_groups
Group.
joins(project_group_links: :project).
where(projects: { namespace_id: id }).
find_each(&:refresh_members_authorized_projects)
Group
.joins(project_group_links: :project)
.where(projects: { namespace_id: id })
.find_each(&:refresh_members_authorized_projects)
end
def remove_exports!
......
......@@ -137,9 +137,9 @@ class Note < ActiveRecord::Base
end
def count_for_collection(ids, type)
user.select('noteable_id', 'COUNT(*) as count').
group(:noteable_id).
where(noteable_type: type, noteable_id: ids)
user.select('noteable_id', 'COUNT(*) as count')
.group(:noteable_id)
.where(noteable_type: type, noteable_id: ids)
end
end
......
......@@ -244,8 +244,8 @@ class Project < ActiveRecord::Base
scope :inside_path, ->(path) do
# We need routes alias rs for JOIN so it does not conflict with
# includes(:route) which we use in ProjectsFinder.
joins("INNER JOIN routes rs ON rs.source_id = projects.id AND rs.source_type = 'Project'").
where('rs.path LIKE ?', "#{sanitize_sql_like(path)}/%")
joins("INNER JOIN routes rs ON rs.source_id = projects.id AND rs.source_type = 'Project'")
.where('rs.path LIKE ?', "#{sanitize_sql_like(path)}/%")
end
# "enabled" here means "not disabled". It includes private features!
......@@ -270,10 +270,10 @@ class Project < ActiveRecord::Base
# logged in user.
def self.public_or_visible_to_user(user = nil)
if user
authorized = user.
project_authorizations.
select(1).
where('project_authorizations.project_id = projects.id')
authorized = user
.project_authorizations
.select(1)
.where('project_authorizations.project_id = projects.id')
levels = Gitlab::VisibilityLevel.levels_for_user(user)
......@@ -298,11 +298,11 @@ class Project < ActiveRecord::Base
elsif user
column = ProjectFeature.quoted_access_level_column(feature)
authorized = user.project_authorizations.select(1).
where('project_authorizations.project_id = projects.id')
authorized = user.project_authorizations.select(1)
.where('project_authorizations.project_id = projects.id')
with_project_feature.
where("#{column} IN (?) OR (#{column} = ? AND EXISTS (?))",
with_project_feature
.where("#{column} IN (?) OR (#{column} = ? AND EXISTS (?))",
visible,
ProjectFeature::PRIVATE,
authorized)
......@@ -369,14 +369,14 @@ class Project < ActiveRecord::Base
# unscoping unnecessary conditions that'll be applied
# when executing `where("projects.id IN (#{union.to_sql})")`
projects = unscoped.select(:id).where(
ptable[:path].matches(pattern).
or(ptable[:name].matches(pattern)).
or(ptable[:description].matches(pattern))
ptable[:path].matches(pattern)
.or(ptable[:name].matches(pattern))
.or(ptable[:description].matches(pattern))
)
namespaces = unscoped.select(:id).
joins(:namespace).
where(ntable[:name].matches(pattern))
namespaces = unscoped.select(:id)
.joins(:namespace)
.where(ntable[:name].matches(pattern))
union = Gitlab::SQL::Union.new([projects, namespaces])
......@@ -417,8 +417,8 @@ class Project < ActiveRecord::Base
end
def trending
joins('INNER JOIN trending_projects ON projects.id = trending_projects.project_id').
reorder('trending_projects.id ASC')
joins('INNER JOIN trending_projects ON projects.id = trending_projects.project_id')
.reorder('trending_projects.id ASC')
end
def cached_count
......
......@@ -7,9 +7,9 @@ class ProjectAuthorization < ActiveRecord::Base
validates :user, uniqueness: { scope: [:project, :access_level] }, presence: true
def self.select_from_union(union)
select(['project_id', 'MAX(access_level) AS access_level']).
from("(#{union.to_sql}) #{ProjectAuthorization.table_name}").
group(:project_id)
select(['project_id', 'MAX(access_level) AS access_level'])
.from("(#{union.to_sql}) #{ProjectAuthorization.table_name}")
.group(:project_id)
end
def self.insert_authorizations(rows, per_batch = 1000)
......
......@@ -20,8 +20,8 @@ class MattermostSlashCommandsService < SlashCommandsService
end
def configure(user, params)
token = Mattermost::Command.new(user).
create(command(params))
token = Mattermost::Command.new(user)
.create(command(params))
update(active: true, token: token) if token
rescue Mattermost::Error => e
......
......@@ -172,10 +172,10 @@ class ProjectTeam
return access if user_ids.empty?
users_access = project.project_authorizations.
where(user: user_ids).
group(:user_id).
maximum(:access_level)
users_access = project.project_authorizations
.where(user: user_ids)
.group(:user_id)
.maximum(:access_level)
access.merge!(users_access)
......
......@@ -241,11 +241,11 @@ class Repository
cache.fetch(:"diverging_commit_counts_#{branch.name}") do
# Rugged seems to throw a `ReferenceError` when given branch_names rather
# than SHA-1 hashes
number_commits_behind = raw_repository.
count_commits_between(branch.dereferenced_target.sha, root_ref_hash)
number_commits_behind = raw_repository
.count_commits_between(branch.dereferenced_target.sha, root_ref_hash)
number_commits_ahead = raw_repository.
count_commits_between(root_ref_hash, branch.dereferenced_target.sha)
number_commits_ahead = raw_repository
.count_commits_between(root_ref_hash, branch.dereferenced_target.sha)
{ behind: number_commits_behind, ahead: number_commits_ahead }
end
......
......@@ -70,9 +70,9 @@ class Todo < ActiveRecord::Base
highest_priority = highest_label_priority(params).to_sql
select("#{table_name}.*, (#{highest_priority}) AS highest_priority").
order(Gitlab::Database.nulls_last_order('highest_priority', 'ASC')).
order('todos.created_at')
select("#{table_name}.*, (#{highest_priority}) AS highest_priority")
.order(Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
.order('todos.created_at')
end
end
......
......@@ -223,13 +223,13 @@ class User < ActiveRecord::Base
scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('last_sign_in_at', 'ASC')) }
def self.with_two_factor
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id").
where("u2f.id IS NOT NULL OR otp_required_for_login = ?", true).distinct(arel_table[:id])
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id")
.where("u2f.id IS NOT NULL OR otp_required_for_login = ?", true).distinct(arel_table[:id])
end
def self.without_two_factor
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id").
where("u2f.id IS NULL AND otp_required_for_login = ?", false)
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id")
.where("u2f.id IS NULL AND otp_required_for_login = ?", false)
end
#
......@@ -300,9 +300,9 @@ class User < ActiveRecord::Base
pattern = "%#{query}%"
where(
table[:name].matches(pattern).
or(table[:email].matches(pattern)).
or(table[:username].matches(pattern))
table[:name].matches(pattern)
.or(table[:email].matches(pattern))
.or(table[:username].matches(pattern))
)
end
......@@ -317,10 +317,10 @@ class User < ActiveRecord::Base
matched_by_emails_user_ids = email_table.project(email_table[:user_id]).where(email_table[:email].matches(pattern))
where(
table[:name].matches(pattern).
or(table[:email].matches(pattern)).
or(table[:username].matches(pattern)).
or(table[:id].in(matched_by_emails_user_ids))
table[:name].matches(pattern)
.or(table[:email].matches(pattern))
.or(table[:username].matches(pattern))
.or(table[:id].in(matched_by_emails_user_ids))
)
end
......@@ -503,8 +503,8 @@ class User < ActiveRecord::Base
# Returns the groups a user has access to
def authorized_groups
union = Gitlab::SQL::Union.
new([groups.select(:id), authorized_projects.select(:namespace_id)])
union = Gitlab::SQL::Union
.new([groups.select(:id), authorized_projects.select(:namespace_id)])
Group.where("namespaces.id IN (#{union.to_sql})")
end
......@@ -533,8 +533,8 @@ class User < ActiveRecord::Base
projects = super()
if min_access_level
projects = projects.
where('project_authorizations.access_level >= ?', min_access_level)
projects = projects
.where('project_authorizations.access_level >= ?', min_access_level)
end
projects
......@@ -619,9 +619,9 @@ class User < ActiveRecord::Base
next unless project
if project.repository.branch_exists?(event.branch_name)
merge_requests = MergeRequest.where("created_at >= ?", event.created_at).
where(source_project_id: project.id,
source_branch: event.branch_name)
merge_requests = MergeRequest.where("created_at >= ?", event.created_at)
.where(source_project_id: project.id,
source_branch: event.branch_name)
merge_requests.empty?
end
end
......@@ -832,8 +832,8 @@ class User < ActiveRecord::Base
def toggle_star(project)
UsersStarProject.transaction do
user_star_project = users_star_projects.
where(project: project, user: self).lock(true).first
user_star_project = users_star_projects
.where(project: project, user: self).lock(true).first
if user_star_project
user_star_project.destroy
......@@ -869,11 +869,11 @@ class User < ActiveRecord::Base
# ms on a database with a similar size to GitLab.com's database. On the other
# hand, using a subquery means we can get the exact same data in about 40 ms.
def contributed_projects
events = Event.select(:project_id).
contributions.where(author_id: self).
where("created_at > ?", Time.now - 1.year).
uniq.
reorder(nil)
events = Event.select(:project_id)
.contributions.where(author_id: self)
.where("created_at > ?", Time.now - 1.year)
.uniq
.reorder(nil)
Project.where(id: events)
end
......@@ -884,9 +884,9 @@ class User < ActiveRecord::Base
def ci_authorized_runners
@ci_authorized_runners ||= begin
runner_ids = Ci::RunnerProject.
where("ci_runner_projects.project_id IN (#{ci_projects_union.to_sql})").
select(:runner_id)
runner_ids = Ci::RunnerProject
.where("ci_runner_projects.project_id IN (#{ci_projects_union.to_sql})")
.select(:runner_id)
Ci::Runner.specific.where(id: runner_ids)
end
end
......
......@@ -22,16 +22,16 @@ class WikiPage
def self.group_by_directory(pages)
return [] if pages.blank?
pages.sort_by { |page| [page.directory, page.slug] }.
group_by(&:directory).
map do |dir, pages|
pages.sort_by { |page| [page.directory, page.slug] }
.group_by(&:directory)
.map do |dir, pages|
if dir.present?
WikiDirectory.new(dir, pages)
else
pages
end
end.
flatten
end
.flatten
end
def self.unhyphenize(name)
......
......@@ -67,8 +67,8 @@ module Ci
def update_merge_requests_head_pipeline
return unless pipeline.latest?
MergeRequest.where(source_project: @pipeline.project, source_branch: @pipeline.ref).
update_all(head_pipeline_id: @pipeline.id)
MergeRequest.where(source_project: @pipeline.project, source_branch: @pipeline.ref)
.update_all(head_pipeline_id: @pipeline.id)
end
def skip_ci?
......
......@@ -3,8 +3,8 @@ module Ci
def execute(project, trigger, ref, variables = nil)
trigger_request = trigger.trigger_requests.create(variables: variables)
pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref).
execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request)
pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref)
.execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request)
trigger_request if pipeline.persisted?
end
......
......@@ -54,15 +54,15 @@ module Ci
def builds_for_shared_runner
new_builds.
# don't run projects which have not enabled shared runners and builds
joins(:project).where(projects: { shared_runners_enabled: true }).
joins('LEFT JOIN project_features ON ci_builds.project_id = project_features.project_id').
where('project_features.builds_access_level IS NULL or project_features.builds_access_level > 0').
joins(:project).where(projects: { shared_runners_enabled: true })
.joins('LEFT JOIN project_features ON ci_builds.project_id = project_features.project_id')
.where('project_features.builds_access_level IS NULL or project_features.builds_access_level > 0').
# Implement fair scheduling
# this returns builds that are ordered by number of running builds
# we prefer projects that don't use shared runners at all
joins("LEFT JOIN (#{running_builds_for_shared_runners.to_sql}) AS project_builds ON ci_builds.project_id=project_builds.project_id").
order('COALESCE(project_builds.running_builds, 0) ASC', 'ci_builds.id ASC')
joins("LEFT JOIN (#{running_builds_for_shared_runners.to_sql}) AS project_builds ON ci_builds.project_id=project_builds.project_id")
.order('COALESCE(project_builds.running_builds, 0) ASC', 'ci_builds.id ASC')
end
def builds_for_specific_runner
......@@ -70,8 +70,8 @@ module Ci
end
def running_builds_for_shared_runners
Ci::Build.running.where(runner: Ci::Runner.shared).
group(:project_id).select(:project_id, 'count(*) AS running_builds')
Ci::Build.running.where(runner: Ci::Runner.shared)
.group(:project_id).select(:project_id, 'count(*) AS running_builds')
end
def new_builds
......
......@@ -10,9 +10,9 @@ module Issues
def merge_request_to_resolve_discussions_of
return @merge_request_to_resolve_discussions_of if defined?(@merge_request_to_resolve_discussions_of)
@merge_request_to_resolve_discussions_of = MergeRequestsFinder.new(current_user, project_id: project.id).
execute.
find_by(iid: merge_request_to_resolve_discussions_of_iid)
@merge_request_to_resolve_discussions_of = MergeRequestsFinder.new(current_user, project_id: project.id)
.execute
.find_by(iid: merge_request_to_resolve_discussions_of_iid)
end
def discussions_to_resolve
......
......@@ -2,7 +2,7 @@ class CreateDeploymentService
attr_reader :job
delegate :expanded_environment_name,
:environment_url,
:variables,
:project,
to: :job
......@@ -14,7 +14,8 @@ class CreateDeploymentService
return unless executable?
ActiveRecord::Base.transaction do
environment.external_url = environment_url if environment_url
environment.external_url = expanded_environment_url if
expanded_environment_url
environment.fire_state_event(action)
return unless environment.save
......@@ -49,6 +50,17 @@ class CreateDeploymentService
@environment_options ||= job.options&.dig(:environment) || {}
end
def expanded_environment_url
return @expanded_environment_url if defined?(@expanded_environment_url)
@expanded_environment_url =
ExpandVariables.expand(environment_url, variables) if environment_url
end
def environment_url
environment_options[:url]
end
def on_stop
environment_options[:on_stop]
end
......
......@@ -28,8 +28,8 @@ module Files
end
def last_commit
@last_commit ||= Gitlab::Git::Commit.
last_for_path(@start_project.repository, @start_branch, @file_path)
@last_commit ||= Gitlab::Git::Commit
.last_for_path(@start_project.repository, @start_branch, @file_path)
end
def validate!
......
......@@ -86,8 +86,8 @@ class GitPushService < BaseService
push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit|
if commit.matches_cross_reference_regex?
ProcessCommitWorker.
perform_async(project.id, current_user.id, commit.to_hash, default)
ProcessCommitWorker
.perform_async(project.id, current_user.id, commit.to_hash, default)
end
end
end
......
......@@ -144,8 +144,8 @@ class IssuableBaseService < BaseService
def merge_quick_actions_into_params!(issuable)
description, command_params =
QuickActions::InterpretService.new(project, current_user).
execute(params[:description], issuable)
QuickActions::InterpretService.new(project, current_user)
.execute(params[:description], issuable)
# Avoid a description already set on an issuable to be overwritten by a nil
params[:description] = description if params.key?(:description)
......
......@@ -30,8 +30,8 @@ module Issues
Discussions::ResolveService.new(project, current_user,
merge_request: merge_request_to_resolve_discussions_of,
follow_up_issue: issue).
execute(discussions_to_resolve)
follow_up_issue: issue)
.execute(discussions_to_resolve)
end
private
......
......@@ -26,29 +26,29 @@ module Labels
private
def label_ids_for_merge(new_label)
LabelsFinder.
new(current_user, title: new_label.title, group_id: project.group.id).
execute(skip_authorization: true).
where.not(id: new_label).
select(:id) # Can't use pluck() to avoid object-creation because of the batching
LabelsFinder
.new(current_user, title: new_label.title, group_id: project.group.id)
.execute(skip_authorization: true)
.where.not(id: new_label)
.select(:id) # Can't use pluck() to avoid object-creation because of the batching
end
def update_issuables(new_label, label_ids)
LabelLink.
where(label: label_ids).
update_all(label_id: new_label)
LabelLink
.where(label: label_ids)
.update_all(label_id: new_label)
end
def update_issue_board_lists(new_label, label_ids)
List.
where(label: label_ids).
update_all(label_id: new_label)
List
.where(label: label_ids)
.update_all(label_id: new_label)
end
def update_priorities(new_label, label_ids)
LabelPriority.
where(label: label_ids).
update_all(label_id: new_label)
LabelPriority
.where(label: label_ids)
.update_all(label_id: new_label)
end
def update_project_labels(label_ids)
......
......@@ -41,16 +41,16 @@ module Labels
end
def group_labels_applied_to_issues
Label.joins(:issues).
where(
Label.joins(:issues)
.where(
issues: { project_id: project.id },
labels: { type: 'GroupLabel', group_id: old_group.id }
)
end
def group_labels_applied_to_merge_requests
Label.joins(:merge_requests).
where(
Label.joins(:merge_requests)
.where(
merge_requests: { target_project_id: project.id },
labels: { type: 'GroupLabel', group_id: old_group.id }
)
......@@ -64,15 +64,15 @@ module Labels
end
def update_label_links(labels, old_label_id:, new_label_id:)
LabelLink.joins(:label).
merge(labels).
where(label_id: old_label_id).
update_all(label_id: new_label_id)
LabelLink.joins(:label)
.merge(labels)
.where(label_id: old_label_id)
.update_all(label_id: new_label_id)
end
def update_label_priorities(old_label_id:, new_label_id:)
LabelPriority.where(project_id: project.id, label_id: old_label_id).
update_all(label_id: new_label_id)
LabelPriority.where(project_id: project.id, label_id: old_label_id)
.update_all(label_id: new_label_id)
end
end
end
......@@ -26,30 +26,30 @@ module Members
def unassign_issues_and_merge_requests(member)
if member.is_a?(GroupMember)
issues = Issue.unscoped.select(1).
joins(:project).
where('issues.id = issue_assignees.issue_id AND projects.namespace_id = ?', member.source_id)
issues = Issue.unscoped.select(1)
.joins(:project)
.where('issues.id = issue_assignees.issue_id AND projects.namespace_id = ?', member.source_id)
# DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
IssueAssignee.unscoped.
where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues).
delete_all
IssueAssignee.unscoped
.where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
.delete_all
MergeRequestsFinder.new(user, group_id: member.source_id, assignee_id: member.user_id).
execute.
update_all(assignee_id: nil)
MergeRequestsFinder.new(user, group_id: member.source_id, assignee_id: member.user_id)
.execute
.update_all(assignee_id: nil)
else
project = member.source
# SELECT 1 FROM issues WHERE issues.id = issue_assignees.issue_id AND issues.project_id = X
issues = Issue.unscoped.select(1).
where('issues.id = issue_assignees.issue_id').
where(project_id: project.id)
issues = Issue.unscoped.select(1)
.where('issues.id = issue_assignees.issue_id')
.where(project_id: project.id)
# DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
IssueAssignee.unscoped.
where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues).
delete_all
IssueAssignee.unscoped
.where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
.delete_all
project.merge_requests.opened.assigned_to(member.user).update_all(assignee_id: nil)
end
......
......@@ -27,10 +27,10 @@ module MergeRequests
tree: merge_index.write_tree(rugged)
}
conflicts_for_resolution.
project.
repository.
resolve_conflicts(current_user, merge_request.source_branch, commit_params)
conflicts_for_resolution
.project
.repository
.resolve_conflicts(current_user, merge_request.source_branch, commit_params)
end
end
......
......@@ -61,8 +61,8 @@ module MergeRequests
MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
if params[:should_remove_source_branch].present? || @merge_request.force_remove_source_branch?
DeleteBranchService.new(@merge_request.source_project, branch_deletion_user).
execute(merge_request.source_branch)
DeleteBranchService.new(@merge_request.source_project, branch_deletion_user)
.execute(merge_request.source_branch)
end
end
......
......@@ -43,9 +43,9 @@ module MergeRequests
end
filter_merge_requests(merge_requests).each do |merge_request|
MergeRequests::PostMergeService.
new(merge_request.target_project, @current_user).
execute(merge_request)
MergeRequests::PostMergeService
.new(merge_request.target_project, @current_user)
.execute(merge_request)
end
end
......@@ -56,8 +56,8 @@ module MergeRequests
# Refresh merge request diff if we push to source or target branch of merge request
# Note: we should update merge requests from forks too
def reload_merge_requests
merge_requests = @project.merge_requests.opened.
by_source_or_target_branch(@branch_name).to_a
merge_requests = @project.merge_requests.opened
.by_source_or_target_branch(@branch_name).to_a
# Fork merge requests
merge_requests += MergeRequest.opened
......
......@@ -22,8 +22,8 @@ module Notes
def extract_commands(note, options = {})
return [note.note, {}] unless supported?(note)
QuickActions::InterpretService.new(project, current_user, options).
execute(note.note, note.noteable)
QuickActions::InterpretService.new(project, current_user, options)
.execute(note.note, note.noteable)
end
def execute(command_params, note)
......
......@@ -19,8 +19,8 @@ module Tags
if new_tag
if release_description
CreateReleaseService.new(@project, @current_user).
execute(tag_name, release_description)
CreateReleaseService.new(@project, @current_user)
.execute(tag_name, release_description)
end
success.merge(tag: new_tag)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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