Commit d251dda4 authored by Luke Bennett's avatar Luke Bennett

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee

parents f2c3523f ad908d16
...@@ -648,6 +648,18 @@ qa:internal: ...@@ -648,6 +648,18 @@ qa:internal:
- bundle install - bundle install
- bundle exec rspec - bundle exec rspec
qa:selectors:
<<: *dedicated-runner
<<: *except-docs
stage: test
variables:
SETUP_DB: "false"
services: []
script:
- cd qa/
- bundle install
- bundle exec bin/qa Test::Sanity::Selectors
coverage: coverage:
<<: *dedicated-runner <<: *dedicated-runner
<<: *except-docs-and-qa <<: *except-docs-and-qa
......
...@@ -397,9 +397,6 @@ gem 'ruby-prof', '~> 0.16.2' ...@@ -397,9 +397,6 @@ gem 'ruby-prof', '~> 0.16.2'
# OAuth # OAuth
gem 'oauth2', '~> 1.4' gem 'oauth2', '~> 1.4'
# Soft deletion
gem 'paranoia', '~> 2.3.1'
# Health check # Health check
gem 'health_check', '~> 2.6.0' gem 'health_check', '~> 2.6.0'
...@@ -422,7 +419,7 @@ group :ed25519 do ...@@ -422,7 +419,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.64.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.69.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.64.0) gitaly-proto (0.69.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)
...@@ -609,8 +609,6 @@ GEM ...@@ -609,8 +609,6 @@ GEM
orm_adapter (0.5.0) orm_adapter (0.5.0)
os (0.9.6) os (0.9.6)
parallel (1.12.0) parallel (1.12.0)
paranoia (2.3.1)
activerecord (>= 4.0, < 5.2)
parser (2.4.0.2) parser (2.4.0.2)
ast (~> 2.3) ast (~> 2.3)
parslet (1.5.0) parslet (1.5.0)
...@@ -1088,7 +1086,7 @@ DEPENDENCIES ...@@ -1088,7 +1086,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.64.0) gitaly-proto (~> 0.69.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)
...@@ -1155,7 +1153,6 @@ DEPENDENCIES ...@@ -1155,7 +1153,6 @@ DEPENDENCIES
omniauth-twitter (~> 1.2.0) omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0) omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
paranoia (~> 2.3.1)
peek (~> 1.0.1) peek (~> 1.0.1)
peek-gc (~> 0.0.2) peek-gc (~> 0.0.2)
peek-host (~> 1.0.0) peek-host (~> 1.0.0)
......
This diff is collapsed.
diff a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js (rejected hunks)
@@ -12,7 +12,6 @@ import notificationsDropdown from './notifications_dropdown';
import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
import LineHighlighter from './line_highlighter';
-import groupsSelect from './groups_select';
import Search from './search';
import initAdmin from './admin';
import NamespaceSelect from './namespace_select';
import { truncate } from './lib/utils/text_utility'; import { truncate } from '../../../lib/utils/text_utility';
const MAX_MESSAGE_LENGTH = 500; const MAX_MESSAGE_LENGTH = 500;
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message'; const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
......
import AbuseReports from './abuse_reports';
export default () => new AbuseReports();
import { refreshCurrentPage } from './lib/utils/url_utility'; import { refreshCurrentPage } from '../../lib/utils/url_utility';
function showBlacklistType() { function showBlacklistType() {
if ($('input[name="blacklist_type"]:checked').val() === 'file') { if ($('input[name="blacklist_type"]:checked').val() === 'file') {
......
import initBroadcastMessagesForm from './broadcast_message';
export default () => initBroadcastMessagesForm();
import initUsagePing from './usage_ping';
export default () => initUsagePing();
import groupAvatar from '../../../../group_avatar';
export default () => groupAvatar();
import BindInOut from '../../../../behaviors/bind_in_out';
import Group from '../../../../group';
import groupAvatar from '../../../../group_avatar';
export default () => {
BindInOut.initAll();
new Group(); // eslint-disable-line no-new
groupAvatar();
};
import UsersSelect from '../../../../users_select';
export default () => new UsersSelect();
import DueDateSelectors from '../../../due_date_select';
export default () => new DueDateSelectors();
import initAdmin from './admin';
export default () => initAdmin();
import Labels from '../../../../labels';
export default () => new Labels();
import Labels from '../../../../labels';
export default () => new Labels();
import ProjectsList from '../../../projects_list';
import NamespaceSelect from '../../../namespace_select';
export default () => {
new ProjectsList(); // eslint-disable-line no-new
document.querySelectorAll('.js-namespace-select')
.forEach(dropdown => new NamespaceSelect({ dropdown }));
};
import Activities from '~/activities';
export default () => new Activities();
import GroupsList from '~/groups_list';
import Landing from '~/landing';
export default function () {
new GroupsList(); // eslint-disable-line no-new
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) return;
const exploreGroupsLanding = new Landing(
landingElement,
landingElement.querySelector('.dismiss-button'),
'explore_groups_landing_dismissed',
);
exploreGroupsLanding.toggle();
}
import ProjectsList from '~/projects_list';
export default () => new ProjectsList();
import VersionCheckImage from '../../version_check_image';
export default () => VersionCheckImage.bindErrorEvent($('img.js-version-status-badge'));
import NotificationsForm from '../../../notifications_form';
import notificationsDropdown from '../../../notifications_dropdown';
export default () => {
new NotificationsForm(); // eslint-disable-line no-new
notificationsDropdown();
};
import DueDateSelectors from '../../../due_date_select';
export default () => new DueDateSelectors();
import Activities from '~/activities';
import ShortcutsNavigation from '~/shortcuts_navigation';
export default function () {
new Activities(); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new
}
import BuildArtifacts from '~/build_artifacts';
import ShortcutsNavigation from '~/shortcuts_navigation';
export default function () {
new ShortcutsNavigation(); // eslint-disable-line no-new
new BuildArtifacts(); // eslint-disable-line no-new
}
import BlobViewer from '~/blob/viewer/index';
import ShortcutsNavigation from '~/shortcuts_navigation';
export default function () {
new ShortcutsNavigation(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
}
import Pipelines from '../../../../pipelines';
export default () => {
const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`;
new Pipelines({ // eslint-disable-line no-new
initTabs: true,
pipelineStatusUrl,
tabsOptions: {
action: controllerAction,
defaultAction: 'pipelines',
parentEl: '.pipelines-tabs',
},
});
};
import NewBranchForm from '../../../../new_branch_form';
export default () => {
new NewBranchForm($('.js-new-pipeline-form')); // eslint-disable-line no-new
};
import memberExpirationDate from '../../../member_expiration_date';
import UsersSelect from '../../../users_select';
import groupsSelect from '../../../groups_select';
import Members from '../../../members';
export default () => {
memberExpirationDate('.js-access-expiration-date-groups');
groupsSelect();
memberExpirationDate();
new Members(); // eslint-disable-line no-new
new UsersSelect(); // eslint-disable-line no-new
};
import Search from './search';
export default () => new Search();
import Flash from './flash'; import Flash from '~/flash';
import Api from './api'; import Api from '~/api';
export default class Search { export default class Search {
constructor() { constructor() {
......
import UsernameValidator from './username_validator';
import SigninTabsMemoizer from './signin_tabs_memoizer';
import OAuthRememberMe from './oauth_remember_me';
export default () => {
new UsernameValidator(); // eslint-disable-line no-new
new SigninTabsMemoizer(); // eslint-disable-line no-new
new OAuthRememberMe({ // eslint-disable-line no-new
container: $('.omniauth-container'),
}).bindEvents();
};
/* eslint no-param-reassign: ["error", { "props": false }]*/ /* eslint no-param-reassign: ["error", { "props": false }]*/
/* eslint no-new: "off" */ /* eslint no-new: "off" */
import AccessorUtilities from './lib/utils/accessor'; import AccessorUtilities from '~/lib/utils/accessor';
/** /**
* Memorize the last selected tab after reloading a page. * Memorize the last selected tab after reloading a page.
......
...@@ -65,6 +65,7 @@ class Admin::RunnersController < Admin::ApplicationController ...@@ -65,6 +65,7 @@ class Admin::RunnersController < Admin::ApplicationController
else else
Project.all Project.all
end end
@projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any? @projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
@projects = @projects.page(params[:page]).per(30) @projects = @projects.page(params[:page]).per(30)
end end
......
...@@ -8,6 +8,7 @@ module GroupTree ...@@ -8,6 +8,7 @@ module GroupTree
# Only show root groups if no parent-id is given # Only show root groups if no parent-id is given
groups.where(parent_id: params[:parent_id]) groups.where(parent_id: params[:parent_id])
end end
@groups = @groups.with_selects_for_list(archived: params[:archived]) @groups = @groups.with_selects_for_list(archived: params[:archived])
.sort(@sort = params[:sort]) .sort(@sort = params[:sort])
.page(params[:page]) .page(params[:page])
......
...@@ -32,6 +32,7 @@ module RoutableActions ...@@ -32,6 +32,7 @@ module RoutableActions
if canonical_path.casecmp(requested_full_path) != 0 if canonical_path.casecmp(requested_full_path) != 0
flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path." flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
end end
redirect_to build_canonical_path(routable) redirect_to build_canonical_path(routable)
end end
end end
......
...@@ -12,6 +12,7 @@ class MetricsController < ActionController::Base ...@@ -12,6 +12,7 @@ class MetricsController < ActionController::Base
) )
"# Metrics are disabled, see: #{help_page}\n" "# Metrics are disabled, see: #{help_page}\n"
end end
render text: response, content_type: 'text/plain; version=0.0.4' render text: response, content_type: 'text/plain; version=0.0.4'
end end
......
...@@ -86,6 +86,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -86,6 +86,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
if ticket if ticket
handle_service_ticket oauth['provider'], ticket handle_service_ticket oauth['provider'], ticket
end end
handle_omniauth handle_omniauth
end end
...@@ -138,6 +139,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -138,6 +139,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Only allow properly saved users to login. # Only allow properly saved users to login.
if @user.persisted? && @user.valid? if @user.persisted? && @user.valid?
log_audit_event(@user, with: oauth['provider']) log_audit_event(@user, with: oauth['provider'])
if @user.two_factor_enabled? if @user.two_factor_enabled?
params[:remember_me] = '1' if remember_me? params[:remember_me] = '1' if remember_me?
prompt_for_two_factor(@user) prompt_for_two_factor(@user)
......
...@@ -150,6 +150,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -150,6 +150,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present? if params[:file].present?
params[:file_name] = params[:file].original_filename params[:file_name] = params[:file].original_filename
end end
File.join(@path, params[:file_name]) File.join(@path, params[:file_name])
elsif params[:file_path].present? elsif params[:file_path].present?
params[:file_path] params[:file_path]
......
...@@ -21,6 +21,7 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -21,6 +21,7 @@ class Projects::HooksController < Projects::ApplicationController
@hooks = @project.hooks.select(&:persisted?) @hooks = @project.hooks.select(&:persisted?)
flash[:alert] = @hook.errors.full_messages.join.html_safe flash[:alert] = @hook.errors.full_messages.join.html_safe
end end
redirect_to project_settings_integrations_path(@project) redirect_to project_settings_integrations_path(@project)
end end
......
...@@ -50,6 +50,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap ...@@ -50,6 +50,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
else else
[] []
end end
@diff_notes_disabled = true @diff_notes_disabled = true
@environment = @merge_request.environments_for(current_user).last @environment = @merge_request.environments_for(current_user).last
......
...@@ -206,6 +206,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -206,6 +206,7 @@ class ProjectsController < Projects::ApplicationController
else else
flash[:alert] = _("Project export could not be deleted.") flash[:alert] = _("Project export could not be deleted.")
end end
redirect_to(edit_project_path(@project)) redirect_to(edit_project_path(@project))
end end
......
...@@ -29,6 +29,7 @@ class SessionsController < Devise::SessionsController ...@@ -29,6 +29,7 @@ class SessionsController < Devise::SessionsController
resource.update_attributes(reset_password_token: nil, resource.update_attributes(reset_password_token: nil,
reset_password_sent_at: nil) reset_password_sent_at: nil)
end end
# hide the signed-in notification # hide the signed-in notification
flash[:notice] = nil flash[:notice] = nil
log_audit_event(current_user, resource, with: authentication_method) log_audit_event(current_user, resource, with: authentication_method)
......
...@@ -63,6 +63,7 @@ class GroupDescendantsFinder ...@@ -63,6 +63,7 @@ class GroupDescendantsFinder
groups_table = Group.arel_table groups_table = Group.arel_table
visible_to_user = groups_table[:visibility_level] visible_to_user = groups_table[:visibility_level]
.in(Gitlab::VisibilityLevel.levels_for_user(current_user)) .in(Gitlab::VisibilityLevel.levels_for_user(current_user))
if current_user if current_user
authorized_groups = GroupsFinder.new(current_user, authorized_groups = GroupsFinder.new(current_user,
all_available: false) all_available: false)
...@@ -115,6 +116,7 @@ class GroupDescendantsFinder ...@@ -115,6 +116,7 @@ class GroupDescendantsFinder
else else
direct_child_groups direct_child_groups
end end
groups.with_selects_for_list(archived: params[:archived]).order_by(sort) groups.with_selects_for_list(archived: params[:archived]).order_by(sort)
end end
...@@ -140,6 +142,7 @@ class GroupDescendantsFinder ...@@ -140,6 +142,7 @@ class GroupDescendantsFinder
else else
direct_child_projects direct_child_projects
end end
projects.with_route.order_by(sort) projects.with_route.order_by(sort)
end end
......
...@@ -34,6 +34,7 @@ class GroupProjectsFinder < ProjectsFinder ...@@ -34,6 +34,7 @@ class GroupProjectsFinder < ProjectsFinder
else else
collection_without_user collection_without_user
end end
union(projects) union(projects)
end end
......
...@@ -62,6 +62,7 @@ module KerberosSpnegoHelper ...@@ -62,6 +62,7 @@ module KerberosSpnegoHelper
else else
nil # accept any valid service principal name from keytab nil # accept any valid service principal name from keytab
end end
gss.acquire_credentials(gss_service_name) # grab credentials from keytab gss.acquire_credentials(gss_service_name) # grab credentials from keytab
# Decode token # Decode token
......
...@@ -203,6 +203,7 @@ module MarkupHelper ...@@ -203,6 +203,7 @@ module MarkupHelper
node.content = node.content.truncate(num_remaining) node.content = node.content.truncate(num_remaining)
truncated = true truncated = true
end end
content_length += node.content.length content_length += node.content.length
end end
......
...@@ -86,6 +86,7 @@ module MergeRequestsHelper ...@@ -86,6 +86,7 @@ module MergeRequestsHelper
approvers_names = merge_request.approvers_left.map(&:name) approvers_names = merge_request.approvers_left.map(&:name)
str << str <<
if more_approvals > 0 if more_approvals > 0
" (from #{render_items_list(approvers_names + ["#{more_approvals} more"])})" " (from #{render_items_list(approvers_names + ["#{more_approvals} more"])})"
elsif more_approvals < 0 elsif more_approvals < 0
......
...@@ -163,6 +163,7 @@ module MilestonesHelper ...@@ -163,6 +163,7 @@ module MilestonesHelper
def show_burndown_placeholder?(warning) def show_burndown_placeholder?(warning)
return false if cookies['hide_burndown_message'].present? return false if cookies['hide_burndown_message'].present?
return false unless @project.feature_available?(:burndown_charts, current_user) && return false unless @project.feature_available?(:burndown_charts, current_user) &&
@project.feature_available?(:issue_weights, current_user) @project.feature_available?(:issue_weights, current_user)
......
...@@ -13,6 +13,7 @@ module NavHelper ...@@ -13,6 +13,7 @@ module NavHelper
current_path?('issues#show') || current_path?('issues#show') ||
current_path?('milestones#show') || current_path?('milestones#show') ||
current_path?('epics#show') current_path?('epics#show')
if cookies[:collapsed_gutter] == 'true' if cookies[:collapsed_gutter] == 'true'
%w[page-gutter right-sidebar-collapsed] %w[page-gutter right-sidebar-collapsed]
else else
......
...@@ -89,6 +89,7 @@ module SnippetsHelper ...@@ -89,6 +89,7 @@ module SnippetsHelper
snippet_chunk = [lined_content[line_number]] snippet_chunk = [lined_content[line_number]]
snippet_start_line = line_number snippet_start_line = line_number
end end
last_line = line_number last_line = line_number
end end
# Add final chunk to chunk array # Add final chunk to chunk array
......
...@@ -58,6 +58,7 @@ module SubmoduleHelper ...@@ -58,6 +58,7 @@ module SubmoduleHelper
url_no_dotgit = url.chomp('.git') url_no_dotgit = url.chomp('.git')
return true if url_no_dotgit == [Gitlab.config.gitlab.url, '/', namespace, '/', return true if url_no_dotgit == [Gitlab.config.gitlab.url, '/', namespace, '/',
project].join('') project].join('')
url_with_dotgit = url_no_dotgit + '.git' url_with_dotgit = url_no_dotgit + '.git'
url_with_dotgit == Gitlab::Shell.new.url_to_repo([namespace, '/', project].join('')) url_with_dotgit == Gitlab::Shell.new.url_to_repo([namespace, '/', project].join(''))
end end
......
...@@ -30,6 +30,7 @@ module TodosHelper ...@@ -30,6 +30,7 @@ module TodosHelper
else else
todo.target_reference todo.target_reference
end end
link_to text, todo_target_path(todo), class: 'has-tooltip', title: todo.target.title link_to text, todo_target_path(todo), class: 'has-tooltip', title: todo.target.title
end end
......
...@@ -465,6 +465,7 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -465,6 +465,7 @@ class ApplicationSetting < ActiveRecord::Base
super(group_full_path) super(group_full_path)
Gitlab::PerformanceBar.expire_allowed_user_ids_cache Gitlab::PerformanceBar.expire_allowed_user_ids_cache
end end
return return
end end
......
...@@ -2,8 +2,9 @@ module Ci ...@@ -2,8 +2,9 @@ module Ci
class PipelineSchedule < ActiveRecord::Base class PipelineSchedule < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
include Importable include Importable
include IgnorableColumn
acts_as_paranoid ignore_column :deleted_at
belongs_to :project belongs_to :project
belongs_to :owner, class_name: 'User' belongs_to :owner, class_name: 'User'
......
module Ci module Ci
class Trigger < ActiveRecord::Base class Trigger < ActiveRecord::Base
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
include IgnorableColumn
acts_as_paranoid ignore_column :deleted_at
belongs_to :project belongs_to :project
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
......
...@@ -10,7 +10,6 @@ module InternalId ...@@ -10,7 +10,6 @@ module InternalId
if iid.blank? if iid.blank?
parent = project || group parent = project || group
records = parent.public_send(self.class.name.tableize) # rubocop:disable GitlabSecurity/PublicSend records = parent.public_send(self.class.name.tableize) # rubocop:disable GitlabSecurity/PublicSend
records = records.with_deleted if self.paranoid?
max_iid = records.maximum(:iid) max_iid = records.maximum(:iid)
self.iid = max_iid.to_i + 1 self.iid = max_iid.to_i + 1
......
...@@ -324,6 +324,7 @@ module Issuable ...@@ -324,6 +324,7 @@ module Issuable
includes = [] includes = []
includes << :author unless notes.authors_loaded? includes << :author unless notes.authors_loaded?
includes << :award_emoji unless notes.award_emojis_loaded? includes << :award_emoji unless notes.award_emojis_loaded?
if includes.any? if includes.any?
notes.includes(includes) notes.includes(includes)
else else
......
...@@ -25,6 +25,7 @@ module LoadedInGroupList ...@@ -25,6 +25,7 @@ module LoadedInGroupList
base_count = projects.project(Arel.star.count.as('preloaded_project_count')) base_count = projects.project(Arel.star.count.as('preloaded_project_count'))
.where(projects[:namespace_id].eq(namespaces[:id])) .where(projects[:namespace_id].eq(namespaces[:id]))
if archived == 'only' if archived == 'only'
base_count.where(projects[:archived].eq(true)) base_count.where(projects[:archived].eq(true))
elsif Gitlab::Utils.to_boolean(archived) elsif Gitlab::Utils.to_boolean(archived)
......
...@@ -16,7 +16,7 @@ class Issue < ActiveRecord::Base ...@@ -16,7 +16,7 @@ class Issue < ActiveRecord::Base
include ThrottledTouch include ThrottledTouch
include IgnorableColumn include IgnorableColumn
ignore_column :assignee_id, :branch_name ignore_column :assignee_id, :branch_name, :deleted_at
WEIGHT_RANGE = 1..9 WEIGHT_RANGE = 1..9
WEIGHT_ALL = 'Everything'.freeze WEIGHT_ALL = 'Everything'.freeze
...@@ -93,8 +93,6 @@ class Issue < ActiveRecord::Base ...@@ -93,8 +93,6 @@ class Issue < ActiveRecord::Base
end end
end end
acts_as_paranoid
class << self class << self
alias_method :in_parents, :in_projects alias_method :in_parents, :in_projects
end end
......
...@@ -135,6 +135,7 @@ class Label < ActiveRecord::Base ...@@ -135,6 +135,7 @@ class Label < ActiveRecord::Base
else else
priorities.find_by(project: project) priorities.find_by(project: project)
end end
priority.try(:priority) priority.try(:priority)
end end
......
...@@ -12,7 +12,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -12,7 +12,8 @@ class MergeRequest < ActiveRecord::Base
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
ignore_column :locked_at, ignore_column :locked_at,
:ref_fetched :ref_fetched,
:deleted_at
include ::EE::MergeRequest include ::EE::MergeRequest
include Elastic::MergeRequestsSearch include Elastic::MergeRequestsSearch
...@@ -155,8 +156,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -155,8 +156,6 @@ class MergeRequest < ActiveRecord::Base
after_save :keep_around_commit after_save :keep_around_commit
acts_as_paranoid
def self.reference_prefix def self.reference_prefix
'!' '!'
end end
...@@ -820,6 +819,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -820,6 +819,7 @@ class MergeRequest < ActiveRecord::Base
if !include_description && closes_issues_references.present? if !include_description && closes_issues_references.present?
message << "Closes #{closes_issues_references.to_sentence}" message << "Closes #{closes_issues_references.to_sentence}"
end end
message << "#{description}" if include_description && description.present? message << "#{description}" if include_description && description.present?
message << "See merge request #{to_reference(full: true)}" message << "See merge request #{to_reference(full: true)}"
......
class Namespace < ActiveRecord::Base class Namespace < ActiveRecord::Base
acts_as_paranoid without_default_scope: true
prepend EE::Namespace prepend EE::Namespace
include CacheMarkdownField include CacheMarkdownField
include Sortable include Sortable
...@@ -11,6 +9,9 @@ class Namespace < ActiveRecord::Base ...@@ -11,6 +9,9 @@ class Namespace < ActiveRecord::Base
include AfterCommitQueue include AfterCommitQueue
include Storage::LegacyNamespace include Storage::LegacyNamespace
include Gitlab::SQL::Pattern include Gitlab::SQL::Pattern
include IgnorableColumn
ignore_column :deleted_at
# Prevent users from creating unreasonably deep level of nesting. # Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of # The number 20 was taken based on maximum nesting level of
...@@ -230,12 +231,6 @@ class Namespace < ActiveRecord::Base ...@@ -230,12 +231,6 @@ class Namespace < ActiveRecord::Base
has_parent? has_parent?
end end
def soft_delete_without_removing_associations
# We can't use paranoia's `#destroy` since this will hard-delete projects.
# Project uses `pending_delete` instead of the acts_as_paranoia gem.
self.deleted_at = Time.now
end
def multiple_issue_boards_available?(user = nil) def multiple_issue_boards_available?(user = nil)
feature_available?(:multiple_issue_boards) feature_available?(:multiple_issue_boards)
end end
......
...@@ -224,6 +224,7 @@ module Network ...@@ -224,6 +224,7 @@ module Network
space_base = parents.first.space space_base = parents.first.space
end end
end end
space_base space_base
end end
......
...@@ -9,6 +9,7 @@ class NotificationRecipient ...@@ -9,6 +9,7 @@ class NotificationRecipient
group: nil, group: nil,
skip_read_ability: false skip_read_ability: false
) )
unless NotificationSetting.levels.key?(type) || type == :subscription unless NotificationSetting.levels.key?(type) || type == :subscription
raise ArgumentError, "invalid type: #{type.inspect}" raise ArgumentError, "invalid type: #{type.inspect}"
end end
......
...@@ -643,6 +643,7 @@ class Project < ActiveRecord::Base ...@@ -643,6 +643,7 @@ class Project < ActiveRecord::Base
project_import_data.data ||= {} project_import_data.data ||= {}
project_import_data.data = project_import_data.data.merge(data) project_import_data.data = project_import_data.data.merge(data)
end end
if credentials if credentials
project_import_data.credentials ||= {} project_import_data.credentials ||= {}
project_import_data.credentials = project_import_data.credentials.merge(credentials) project_import_data.credentials = project_import_data.credentials.merge(credentials)
......
...@@ -110,6 +110,7 @@ class HipchatService < Service ...@@ -110,6 +110,7 @@ class HipchatService < Service
message = "" message = ""
message << "#{push[:user_name]} " message << "#{push[:user_name]} "
if Gitlab::Git.blank_ref?(before) if Gitlab::Git.blank_ref?(before)
message << "pushed new #{ref_type} <a href=\""\ message << "pushed new #{ref_type} <a href=\""\
"#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"\ "#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"\
......
...@@ -110,6 +110,10 @@ class Repository ...@@ -110,6 +110,10 @@ class Repository
"#<#{self.class.name}:#{@disk_path}>" "#<#{self.class.name}:#{@disk_path}>"
end end
def create_hooks
Gitlab::Git::Repository.create_hooks(path_to_repo, Gitlab.config.gitlab_shell.hooks_path)
end
def commit(ref = 'HEAD') def commit(ref = 'HEAD')
return nil unless exists? return nil unless exists?
return ref if ref.is_a?(::Commit) return ref if ref.is_a?(::Commit)
...@@ -1069,6 +1073,7 @@ class Repository ...@@ -1069,6 +1073,7 @@ class Repository
else else
cache.fetch(key, &block) cache.fetch(key, &block)
end end
instance_variable_set(ivar, value) instance_variable_set(ivar, value)
rescue Rugged::ReferenceError, Gitlab::Git::Repository::NoRepository rescue Rugged::ReferenceError, Gitlab::Git::Repository::NoRepository
# Even if the above `#exists?` check passes these errors might still # Even if the above `#exists?` check passes these errors might still
......
...@@ -252,6 +252,7 @@ class Service < ActiveRecord::Base ...@@ -252,6 +252,7 @@ class Service < ActiveRecord::Base
teamcity teamcity
microsoft_teams microsoft_teams
] ]
if Rails.env.development? if Rails.env.development?
service_names += %w[mock_ci mock_deployment mock_monitoring] service_names += %w[mock_ci mock_deployment mock_monitoring]
end end
......
...@@ -6,7 +6,6 @@ class IssueEntity < IssuableEntity ...@@ -6,7 +6,6 @@ class IssueEntity < IssuableEntity
expose :updated_by_id expose :updated_by_id
expose :created_at expose :created_at
expose :updated_at expose :updated_at
expose :deleted_at
expose :milestone, using: API::Entities::Milestone expose :milestone, using: API::Entities::Milestone
expose :labels, using: LabelEntity expose :labels, using: LabelEntity
expose :lock_version expose :lock_version
......
...@@ -16,6 +16,7 @@ class CreateDeploymentService ...@@ -16,6 +16,7 @@ class CreateDeploymentService
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
environment.external_url = expanded_environment_url if environment.external_url = expanded_environment_url if
expanded_environment_url expanded_environment_url
environment.fire_state_event(action) environment.fire_state_event(action)
return unless environment.save return unless environment.save
......
...@@ -3,7 +3,6 @@ module Groups ...@@ -3,7 +3,6 @@ module Groups
prepend ::EE::Groups::DestroyService prepend ::EE::Groups::DestroyService
def async_execute def async_execute
group.soft_delete_without_removing_associations
job_id = GroupDestroyWorker.perform_async(group.id, current_user.id) job_id = GroupDestroyWorker.perform_async(group.id, current_user.id)
Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}") Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}")
end end
...@@ -25,7 +24,7 @@ module Groups ...@@ -25,7 +24,7 @@ module Groups
group.chat_team&.remove_mattermost_team(current_user) group.chat_team&.remove_mattermost_team(current_user)
group.really_destroy! group.destroy
end end
end end
end end
...@@ -59,7 +59,7 @@ module Users ...@@ -59,7 +59,7 @@ module Users
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
user_data = user.destroy user_data = user.destroy
namespace.really_destroy! namespace.destroy
user_data user_data
end end
......
%header.navbar.navbar-gitlab.navbar-gitlab-new %header.navbar.navbar-gitlab.navbar-gitlab-new.qa-navbar
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid .container-fluid
.header-content .header-content
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
= todos_count_format(todos_pending_count) = todos_count_format(todos_pending_count)
%li.header-user.dropdown %li.header-user.dropdown
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon(current_user, 23), width: 23, height: 23, class: "header-user-avatar" = image_tag avatar_icon(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar"
= sprite_icon('angle-down', css_class: 'caret-down') = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu-nav.dropdown-menu-align-right .dropdown-menu-nav.dropdown-menu-align-right
%ul %ul
......
%ul.list-unstyled.navbar-sub-nav %ul.list-unstyled.navbar-sub-nav
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects" }) do = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown" }) do
%a{ href: "#", data: { toggle: "dropdown" } } %a{ href: "#", data: { toggle: "dropdown" } }
Projects Projects
= sprite_icon('angle-down', css_class: 'caret-down') = sprite_icon('angle-down', css_class: 'caret-down')
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= render "layouts/nav/projects_dropdown/show" = render "layouts/nav/projects_dropdown/show"
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "hidden-xs" }) do = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "hidden-xs" }) do
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do = link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups qa-groups-link', title: 'Groups' do
Groups Groups
= nav_link(path: 'dashboard#activity', html_options: { class: "visible-lg" }) do = nav_link(path: 'dashboard#activity', html_options: { class: "visible-lg" }) do
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
%li.line-separator.hidden-xs %li.line-separator.hidden-xs
- if current_user.admin? - if current_user.admin?
= nav_link(controller: 'admin/dashboard') do = nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'admin-icon', title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('admin', size: 18) = sprite_icon('admin', size: 18)
- if Gitlab::Sherlock.enabled? - if Gitlab::Sherlock.enabled?
%li %li
......
- project_meta = { id: @project.id, name: @project.name, namespace: @project.name_with_namespace, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted? - project_meta = { id: @project.id, name: @project.name, namespace: @project.name_with_namespace, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted?
.projects-dropdown-container .projects-dropdown-container
.project-dropdown-sidebar .project-dropdown-sidebar.qa-projects-dropdown-sidebar
%ul %ul
= nav_link(path: 'dashboard/projects#index') do = nav_link(path: 'dashboard/projects#index') do
= link_to dashboard_projects_path do = link_to dashboard_projects_path, class: 'qa-your-projects-link' do
= _('Your projects') = _('Your projects')
= nav_link(path: 'projects#starred') do = nav_link(path: 'projects#starred') do
= link_to starred_dashboard_projects_path do = link_to starred_dashboard_projects_path do
......
...@@ -240,7 +240,7 @@ ...@@ -240,7 +240,7 @@
= link_to edit_project_path(@project), class: 'shortcuts-tree' do = link_to edit_project_path(@project), class: 'shortcuts-tree' do
.nav-icon-container .nav-icon-container
= sprite_icon('settings') = sprite_icon('settings')
%span.nav-item-name %span.nav-item-name.qa-settings-item
Settings Settings
%ul.sidebar-sub-level-items %ul.sidebar-sub-level-items
......
...@@ -4,7 +4,7 @@ class GroupDestroyWorker ...@@ -4,7 +4,7 @@ class GroupDestroyWorker
def perform(group_id, user_id) def perform(group_id, user_id)
begin begin
group = Group.with_deleted.find(group_id) group = Group.find(group_id)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
return return
end end
......
...@@ -13,6 +13,7 @@ class PagesWorker ...@@ -13,6 +13,7 @@ class PagesWorker
if result[:status] == :success if result[:status] == :success
result = Projects::UpdatePagesConfigurationService.new(build.project).execute result = Projects::UpdatePagesConfigurationService.new(build.project).execute
end end
result result
end end
......
---
title: Adds Rubocop rule for line break around conditionals
merge_request: 15739
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Remove soft removals related code
merge_request: 15789
author:
type: changed
---
title: Fix hooks not being set up properly for bare import Rake task
merge_request:
author:
type: fixed
...@@ -166,6 +166,7 @@ module Gitlab ...@@ -166,6 +166,7 @@ module Gitlab
caching_config_hash[:pool_size] = Sidekiq.options[:concurrency] + 5 caching_config_hash[:pool_size] = Sidekiq.options[:concurrency] + 5
caching_config_hash[:pool_timeout] = 1 caching_config_hash[:pool_timeout] = 1
end end
config.cache_store = :redis_store, caching_config_hash config.cache_store = :redis_store, caching_config_hash
config.active_record.raise_in_transactional_callbacks = true config.active_record.raise_in_transactional_callbacks = true
......
...@@ -93,6 +93,7 @@ class Settings < Settingslogic ...@@ -93,6 +93,7 @@ class Settings < Settingslogic
end end
values.delete_if { |value| value.nil? } values.delete_if { |value| value.nil? }
end end
values values
end end
...@@ -103,6 +104,7 @@ class Settings < Settingslogic ...@@ -103,6 +104,7 @@ class Settings < Settingslogic
if current.is_a? String if current.is_a? String
value = modul.const_get(current.upcase) rescue default value = modul.const_get(current.upcase) rescue default
end end
value value
end end
......
...@@ -241,6 +241,7 @@ Devise.setup do |config| ...@@ -241,6 +241,7 @@ Devise.setup do |config|
true true
end end
end end
if provider['name'] == 'authentiq' if provider['name'] == 'authentiq'
provider['args'][:remote_sign_out_handler] = lambda do |request| provider['args'][:remote_sign_out_handler] = lambda do |request|
authentiq_session = request.params['sid'] authentiq_session = request.params['sid']
......
...@@ -2,6 +2,7 @@ Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Re ...@@ -2,6 +2,7 @@ Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Re
Peek.into Peek::Views::Host Peek.into Peek::Views::Host
Peek.into Peek::Views::PerformanceBar Peek.into Peek::Views::PerformanceBar
if Gitlab::Database.mysql? if Gitlab::Database.mysql?
require 'peek-mysql2' require 'peek-mysql2'
PEEK_DB_CLIENT = ::Mysql2::Client PEEK_DB_CLIENT = ::Mysql2::Client
...@@ -11,6 +12,7 @@ else ...@@ -11,6 +12,7 @@ else
PEEK_DB_CLIENT = ::PG::Connection PEEK_DB_CLIENT = ::PG::Connection
PEEK_DB_VIEW = Peek::Views::PG PEEK_DB_VIEW = Peek::Views::PG
end end
Peek.into PEEK_DB_VIEW Peek.into PEEK_DB_VIEW
Peek.into Peek::Views::Redis Peek.into Peek::Views::Redis
Peek.into Peek::Views::Sidekiq Peek.into Peek::Views::Sidekiq
......
...@@ -23,6 +23,7 @@ class CreateForkNetworks < ActiveRecord::Migration ...@@ -23,6 +23,7 @@ class CreateForkNetworks < ActiveRecord::Migration
if foreign_keys_for(:fork_networks, :root_project_id).any? if foreign_keys_for(:fork_networks, :root_project_id).any?
remove_foreign_key :fork_networks, column: :root_project_id remove_foreign_key :fork_networks, column: :root_project_id
end end
drop_table :fork_networks drop_table :fork_networks
end end
end end
...@@ -21,6 +21,7 @@ class CreateForkNetworkMembers < ActiveRecord::Migration ...@@ -21,6 +21,7 @@ class CreateForkNetworkMembers < ActiveRecord::Migration
if foreign_keys_for(:fork_network_members, :forked_from_project_id).any? if foreign_keys_for(:fork_network_members, :forked_from_project_id).any?
remove_foreign_key :fork_network_members, column: :forked_from_project_id remove_foreign_key :fork_network_members, column: :forked_from_project_id
end end
drop_table :fork_network_members drop_table :fork_network_members
end end
end end
...@@ -9,6 +9,7 @@ class AddIndexOnNamespacesLowerName < ActiveRecord::Migration ...@@ -9,6 +9,7 @@ class AddIndexOnNamespacesLowerName < ActiveRecord::Migration
return unless Gitlab::Database.postgresql? return unless Gitlab::Database.postgresql?
disable_statement_timeout disable_statement_timeout
if Gitlab::Database.version.to_f >= 9.5 if Gitlab::Database.version.to_f >= 9.5
# Allow us to hot-patch the index manually ahead of the migration # Allow us to hot-patch the index manually ahead of the migration
execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS #{INDEX_NAME} ON namespaces (lower(name));" execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS #{INDEX_NAME} ON namespaces (lower(name));"
...@@ -21,6 +22,7 @@ class AddIndexOnNamespacesLowerName < ActiveRecord::Migration ...@@ -21,6 +22,7 @@ class AddIndexOnNamespacesLowerName < ActiveRecord::Migration
return unless Gitlab::Database.postgresql? return unless Gitlab::Database.postgresql?
disable_statement_timeout disable_statement_timeout
if Gitlab::Database.version.to_f >= 9.2 if Gitlab::Database.version.to_f >= 9.2
execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME};" execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME};"
else else
......
...@@ -31,6 +31,7 @@ class RenameUsersWithRenamedNamespace < ActiveRecord::Migration ...@@ -31,6 +31,7 @@ class RenameUsersWithRenamedNamespace < ActiveRecord::Migration
predicate = namespaces[:owner_id].eq(users[:id]) predicate = namespaces[:owner_id].eq(users[:id])
.and(namespaces[:type].eq(nil)) .and(namespaces[:type].eq(nil))
.and(users[:username].matches(path)) .and(users[:username].matches(path))
update_sql = if Gitlab::Database.postgresql? update_sql = if Gitlab::Database.postgresql?
"UPDATE users SET username = namespaces.path "\ "UPDATE users SET username = namespaces.path "\
"FROM namespaces WHERE #{predicate.to_sql}" "FROM namespaces WHERE #{predicate.to_sql}"
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveSoftRemovedObjects < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
module SoftRemoved
extend ActiveSupport::Concern
included do
scope :soft_removed, -> { where('deleted_at IS NOT NULL') }
end
end
class User < ActiveRecord::Base
self.table_name = 'users'
include EachBatch
end
class Issue < ActiveRecord::Base
self.table_name = 'issues'
include EachBatch
include SoftRemoved
end
class MergeRequest < ActiveRecord::Base
self.table_name = 'merge_requests'
include EachBatch
include SoftRemoved
end
class Namespace < ActiveRecord::Base
self.table_name = 'namespaces'
include EachBatch
include SoftRemoved
scope :soft_removed_personal, -> { soft_removed.where(type: nil) }
scope :soft_removed_group, -> { soft_removed.where(type: 'Group') }
end
class Route < ActiveRecord::Base
self.table_name = 'routes'
include EachBatch
include SoftRemoved
end
class Project < ActiveRecord::Base
self.table_name = 'projects'
include EachBatch
include SoftRemoved
end
class CiPipelineSchedule < ActiveRecord::Base
self.table_name = 'ci_pipeline_schedules'
include EachBatch
include SoftRemoved
end
class CiTrigger < ActiveRecord::Base
self.table_name = 'ci_triggers'
include EachBatch
include SoftRemoved
end
MODELS = [Issue, MergeRequest, CiPipelineSchedule, CiTrigger].freeze
def up
disable_statement_timeout
remove_personal_routes
remove_personal_namespaces
remove_group_namespaces
remove_simple_soft_removed_rows
end
def down
# The data removed by this migration can't be restored in an automated way.
end
def remove_simple_soft_removed_rows
create_temporary_indexes
MODELS.each do |model|
say_with_time("Removing soft removed rows from #{model.table_name}") do
model.soft_removed.each_batch do |batch, index|
batch.delete_all
end
end
end
ensure
remove_temporary_indexes
end
def create_temporary_indexes
MODELS.each do |model|
index_name = temporary_index_name_for(model)
# Without this index the removal process can take a very long time. For
# example, getting the next ID of a batch for the `issues` table in
# staging would take between 15 and 20 seconds.
next if temporary_index_exists?(model)
say_with_time("Creating temporary index #{index_name}") do
add_concurrent_index(
model.table_name,
[:deleted_at, :id],
name: index_name,
where: 'deleted_at IS NOT NULL'
)
end
end
end
def remove_temporary_indexes
MODELS.each do |model|
index_name = temporary_index_name_for(model)
next unless temporary_index_exists?(model)
say_with_time("Removing temporary index #{index_name}") do
remove_concurrent_index_by_name(model.table_name, index_name)
end
end
end
def temporary_index_name_for(model)
"index_on_#{model.table_name}_tmp"
end
def temporary_index_exists?(model)
index_name = temporary_index_name_for(model)
index_exists?(model.table_name, [:deleted_at, :id], name: index_name)
end
def remove_personal_namespaces
# Some personal namespaces are left behind in case of GitLab.com. In these
# cases the associated data such as the projects and users has already been
# removed.
Namespace.soft_removed_personal.each_batch do |batch|
batch.delete_all
end
end
def remove_group_namespaces
admin_id = id_for_admin_user
unless admin_id
say 'Not scheduling soft removed groups for removal as no admin user ' \
'could be found. You will need to remove any such groups manually.'
return
end
# Left over groups can't be easily removed because we may also need to
# remove memberships, repositories, and other associated data. As a result
# we'll just schedule a Sidekiq job to remove these.
#
# As of January 5th, 2018 there are 36 groups that will be removed using
# this code.
Namespace.select(:id).soft_removed_group.each_batch(of: 10) do |batch, index|
batch.each do |ns|
schedule_group_removal(index * 5.minutes, ns.id, admin_id)
end
end
end
def schedule_group_removal(delay, group_id, user_id)
if migrate_inline?
GroupDestroyWorker.new.perform(group_id, user_id)
else
GroupDestroyWorker.perform_in(delay, group_id, user_id)
end
end
def remove_personal_routes
namespaces = Namespace.select(1)
.soft_removed
.where('namespaces.type IS NULL')
.where('routes.source_type = ?', 'Namespace')
.where('routes.source_id = namespaces.id')
Route.where('EXISTS (?)', namespaces).each_batch do |batch|
batch.delete_all
end
end
def id_for_admin_user
User.where(admin: true).limit(1).pluck(:id).first
end
def migrate_inline?
Rails.env.test? || Rails.env.development?
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveDeletedAtColumns < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
TABLES = %i[issues merge_requests namespaces ci_pipeline_schedules ci_triggers].freeze
COLUMN = :deleted_at
def up
TABLES.each do |table|
remove_column(table, COLUMN) if column_exists?(table, COLUMN)
end
end
def down
TABLES.each do |table|
unless column_exists?(table, COLUMN)
add_column(table, COLUMN, :datetime_with_timezone)
end
unless index_exists?(table, COLUMN)
add_concurrent_index(table, COLUMN)
end
end
end
end
...@@ -434,7 +434,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -434,7 +434,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
t.integer "project_id" t.integer "project_id"
t.integer "owner_id" t.integer "owner_id"
t.boolean "active", default: true t.boolean "active", default: true
t.datetime "deleted_at"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
end end
...@@ -558,7 +557,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -558,7 +557,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
create_table "ci_triggers", force: :cascade do |t| create_table "ci_triggers", force: :cascade do |t|
t.string "token" t.string "token"
t.datetime "deleted_at"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.integer "project_id" t.integer "project_id"
...@@ -1198,7 +1196,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1198,7 +1196,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
t.integer "updated_by_id" t.integer "updated_by_id"
t.integer "weight" t.integer "weight"
t.boolean "confidential", default: false, null: false t.boolean "confidential", default: false, null: false
t.datetime "deleted_at"
t.date "due_date" t.date "due_date"
t.integer "moved_to_id" t.integer "moved_to_id"
t.integer "lock_version" t.integer "lock_version"
...@@ -1216,7 +1213,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1216,7 +1213,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree
add_index "issues", ["confidential"], name: "index_issues_on_confidential", using: :btree add_index "issues", ["confidential"], name: "index_issues_on_confidential", using: :btree
add_index "issues", ["deleted_at"], name: "index_issues_on_deleted_at", using: :btree
add_index "issues", ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} add_index "issues", ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree
add_index "issues", ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree add_index "issues", ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree
...@@ -1444,7 +1440,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1444,7 +1440,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
t.boolean "merge_when_pipeline_succeeds", default: false, null: false t.boolean "merge_when_pipeline_succeeds", default: false, null: false
t.integer "merge_user_id" t.integer "merge_user_id"
t.string "merge_commit_sha" t.string "merge_commit_sha"
t.datetime "deleted_at"
t.integer "approvals_before_merge" t.integer "approvals_before_merge"
t.string "rebase_commit_sha" t.string "rebase_commit_sha"
t.string "in_progress_merge_commit_sha" t.string "in_progress_merge_commit_sha"
...@@ -1465,7 +1460,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1465,7 +1460,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
add_index "merge_requests", ["created_at"], name: "index_merge_requests_on_created_at", using: :btree add_index "merge_requests", ["created_at"], name: "index_merge_requests_on_created_at", using: :btree
add_index "merge_requests", ["deleted_at"], name: "index_merge_requests_on_deleted_at", using: :btree
add_index "merge_requests", ["description"], name: "index_merge_requests_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} add_index "merge_requests", ["description"], name: "index_merge_requests_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
add_index "merge_requests", ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id", using: :btree add_index "merge_requests", ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id", using: :btree
add_index "merge_requests", ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id", using: :btree add_index "merge_requests", ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id", using: :btree
...@@ -1539,7 +1533,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1539,7 +1533,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
t.datetime "ldap_sync_last_update_at" t.datetime "ldap_sync_last_update_at"
t.datetime "ldap_sync_last_successful_update_at" t.datetime "ldap_sync_last_successful_update_at"
t.datetime "ldap_sync_last_sync_at" t.datetime "ldap_sync_last_sync_at"
t.datetime "deleted_at"
t.text "description_html" t.text "description_html"
t.boolean "lfs_enabled" t.boolean "lfs_enabled"
t.integer "parent_id" t.integer "parent_id"
...@@ -1552,7 +1545,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1552,7 +1545,6 @@ ActiveRecord::Schema.define(version: 20180105233807) do
end end
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
add_index "namespaces", ["deleted_at"], name: "index_namespaces_on_deleted_at", using: :btree
add_index "namespaces", ["ldap_sync_last_successful_update_at"], name: "index_namespaces_on_ldap_sync_last_successful_update_at", using: :btree add_index "namespaces", ["ldap_sync_last_successful_update_at"], name: "index_namespaces_on_ldap_sync_last_successful_update_at", using: :btree
add_index "namespaces", ["ldap_sync_last_update_at"], name: "index_namespaces_on_ldap_sync_last_update_at", using: :btree add_index "namespaces", ["ldap_sync_last_update_at"], name: "index_namespaces_on_ldap_sync_last_update_at", using: :btree
add_index "namespaces", ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree add_index "namespaces", ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree
......
# Epics API # Epics API
Every API call to epic_issues must be authenticated. Every API call to epic must be authenticated.
If a user is not a member of a group and the group is private, a `GET` request on that group will result to a `404` status code. If a user is not a member of a group and the group is private, a `GET` request on that group will result to a `404` status code.
Epics are available only in EEU. If epics feature is not available a `403` status code will be returned. Epics are available only in EEU. If epics feature is not available a `403` status code will be returned.
## Epic issues API
The [epic issues API](epic_issues.md) allows you to interact with issues associated with an epic.
## List epics for a group ## List epics for a group
Gets all epics of the requested group. Gets all epics of the requested group.
...@@ -186,3 +190,4 @@ DELETE /groups/:id/-/epics/:epic_iid ...@@ -186,3 +190,4 @@ DELETE /groups/:id/-/epics/:epic_iid
```bash ```bash
curl --header DELETE "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/1/-/epics/5?title=New%20Title curl --header DELETE "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/1/-/epics/5?title=New%20Title
``` ```
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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