Commit 233d3597 authored by Sincheol (David) Kim's avatar Sincheol (David) Kim

Merge branch '344013_remove_projects_pending_deletion_from_ui' into 'master'

Remove projects that are marked for deletion from UI

See merge request gitlab-org/gitlab!75742
parents 5afadbcf 3d645a70
...@@ -35,7 +35,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -35,7 +35,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def starred def starred
@projects = load_projects(params.merge(starred: true)) @projects = load_projects(params.merge(starred: true, not_aimed_for_deletion: true))
.includes(:forked_from_project, :topics) .includes(:forked_from_project, :topics)
@groups = [] @groups = []
...@@ -54,7 +54,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -54,7 +54,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private private
def projects def projects
@projects ||= load_projects(params.merge(non_public: true)) @projects ||= load_projects(params.merge(non_public: true, not_aimed_for_deletion: true))
end end
def render_projects def render_projects
...@@ -65,8 +65,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -65,8 +65,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end end
def load_projects(finder_params) def load_projects(finder_params)
@total_user_projects_count = ProjectsFinder.new(params: { non_public: true, without_deleted: true }, current_user: current_user).execute @total_user_projects_count = ProjectsFinder.new(params: { non_public: true, without_deleted: true, not_aimed_for_deletion: true }, current_user: current_user).execute
@total_starred_projects_count = ProjectsFinder.new(params: { starred: true, without_deleted: true }, current_user: current_user).execute @total_starred_projects_count = ProjectsFinder.new(params: { starred: true, without_deleted: true, not_aimed_for_deletion: true }, current_user: current_user).execute
finder_params[:use_cte] = true if use_cte_for_finder? finder_params[:use_cte] = true if use_cte_for_finder?
finder_params[:without_deleted] = true finder_params[:without_deleted] = true
......
...@@ -92,7 +92,12 @@ class Explore::ProjectsController < Explore::ApplicationController ...@@ -92,7 +92,12 @@ class Explore::ProjectsController < Explore::ApplicationController
def load_projects def load_projects
load_project_counts load_project_counts
projects = ProjectsFinder.new(current_user: current_user, params: params.merge(minimum_search_length: MIN_SEARCH_LENGTH)).execute finder_params = {
minimum_search_length: MIN_SEARCH_LENGTH,
not_aimed_for_deletion: true
}
projects = ProjectsFinder.new(current_user: current_user, params: params.merge(finder_params)).execute
projects = preload_associations(projects) projects = preload_associations(projects)
projects = projects.page(params[:page]).without_count projects = projects.page(params[:page]).without_count
......
...@@ -186,7 +186,7 @@ class UsersController < ApplicationController ...@@ -186,7 +186,7 @@ class UsersController < ApplicationController
end end
def starred_projects def starred_projects
StarredProjectsFinder.new(user, current_user: current_user).execute StarredProjectsFinder.new(user, params: finder_params, current_user: current_user).execute
end end
def contributions_calendar def contributions_calendar
...@@ -252,6 +252,15 @@ class UsersController < ApplicationController ...@@ -252,6 +252,15 @@ class UsersController < ApplicationController
end end
end end
end end
def finder_params
{
# don't display projects pending deletion
without_deleted: true,
# don't display projects marked for deletion
not_aimed_for_deletion: true
}
end
end end
UsersController.prepend_mod_with('UsersController') UsersController.prepend_mod_with('UsersController')
...@@ -25,7 +25,7 @@ class GroupDescendantsFinder ...@@ -25,7 +25,7 @@ class GroupDescendantsFinder
def initialize(current_user: nil, parent_group:, params: {}) def initialize(current_user: nil, parent_group:, params: {})
@current_user = current_user @current_user = current_user
@parent_group = parent_group @parent_group = parent_group
@params = params.reverse_merge(non_archived: params[:archived].blank?) @params = params.reverse_merge(non_archived: params[:archived].blank?, not_aimed_for_deletion: true)
end end
def execute def execute
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
# last_activity_before: datetime # last_activity_before: datetime
# repository_storage: string # repository_storage: string
# without_deleted: boolean # without_deleted: boolean
# not_aimed_for_deletion: boolean
# #
class ProjectsFinder < UnionFinder class ProjectsFinder < UnionFinder
include CustomAttributesFilter include CustomAttributesFilter
...@@ -84,6 +85,7 @@ class ProjectsFinder < UnionFinder ...@@ -84,6 +85,7 @@ class ProjectsFinder < UnionFinder
collection = by_archived(collection) collection = by_archived(collection)
collection = by_custom_attributes(collection) collection = by_custom_attributes(collection)
collection = by_deleted_status(collection) collection = by_deleted_status(collection)
collection = by_not_aimed_for_deletion(collection)
collection = by_last_activity_after(collection) collection = by_last_activity_after(collection)
collection = by_last_activity_before(collection) collection = by_last_activity_before(collection)
by_repository_storage(collection) by_repository_storage(collection)
...@@ -203,6 +205,10 @@ class ProjectsFinder < UnionFinder ...@@ -203,6 +205,10 @@ class ProjectsFinder < UnionFinder
params[:without_deleted].present? ? items.without_deleted : items params[:without_deleted].present? ? items.without_deleted : items
end end
def by_not_aimed_for_deletion(items)
params[:not_aimed_for_deletion].present? ? items.not_aimed_for_deletion : items
end
def by_last_activity_after(items) def by_last_activity_after(items)
if params[:last_activity_after].present? if params[:last_activity_after].present?
items.where("last_activity_at > ?", params[:last_activity_after]) # rubocop: disable CodeReuse/ActiveRecord items.where("last_activity_at > ?", params[:last_activity_after]) # rubocop: disable CodeReuse/ActiveRecord
......
...@@ -511,6 +511,7 @@ class Project < ApplicationRecord ...@@ -511,6 +511,7 @@ class Project < ApplicationRecord
# Scopes # Scopes
scope :pending_delete, -> { where(pending_delete: true) } scope :pending_delete, -> { where(pending_delete: true) }
scope :without_deleted, -> { where(pending_delete: false) } scope :without_deleted, -> { where(pending_delete: false) }
scope :not_aimed_for_deletion, -> { where(marked_for_deletion_at: nil).without_deleted }
scope :with_storage_feature, ->(feature) do scope :with_storage_feature, ->(feature) do
where(arel_table[:storage_version].gteq(HASHED_STORAGE_FEATURES[feature])) where(arel_table[:storage_version].gteq(HASHED_STORAGE_FEATURES[feature]))
......
...@@ -1593,7 +1593,7 @@ class User < ApplicationRecord ...@@ -1593,7 +1593,7 @@ class User < ApplicationRecord
.distinct .distinct
.reorder(nil) .reorder(nil)
Project.where(id: events) Project.where(id: events).not_aimed_for_deletion
end end
def can_be_removed? def can_be_removed?
......
...@@ -158,7 +158,6 @@ module EE ...@@ -158,7 +158,6 @@ module EE
scope :with_slack_integration, -> { joins(:slack_integration) } scope :with_slack_integration, -> { joins(:slack_integration) }
scope :with_slack_slash_commands_integration, -> { joins(:slack_slash_commands_integration) } scope :with_slack_slash_commands_integration, -> { joins(:slack_slash_commands_integration) }
scope :aimed_for_deletion, -> (date) { where('marked_for_deletion_at <= ?', date).without_deleted } scope :aimed_for_deletion, -> (date) { where('marked_for_deletion_at <= ?', date).without_deleted }
scope :not_aimed_for_deletion, -> { where(marked_for_deletion_at: nil) }
scope :with_repos_templates, -> { where(namespace_id: ::Gitlab::CurrentSettings.current_application_settings.custom_project_templates_group_id) } scope :with_repos_templates, -> { where(namespace_id: ::Gitlab::CurrentSettings.current_application_settings.custom_project_templates_group_id) }
scope :with_groups_level_repos_templates, -> { joins("INNER JOIN namespaces ON projects.namespace_id = namespaces.custom_project_templates_group_id") } scope :with_groups_level_repos_templates, -> { joins("INNER JOIN namespaces ON projects.namespace_id = namespaces.custom_project_templates_group_id") }
scope :with_designs, -> { where(id: ::DesignManagement::Design.select(:project_id).distinct) } scope :with_designs, -> { where(id: ::DesignManagement::Design.select(:project_id).distinct) }
......
...@@ -52,11 +52,19 @@ RSpec.describe ProjectsFinder do ...@@ -52,11 +52,19 @@ RSpec.describe ProjectsFinder do
context 'filter by aimed for deletion' do context 'filter by aimed for deletion' do
let_it_be(:params) { { aimed_for_deletion: true } } let_it_be(:params) { { aimed_for_deletion: true } }
let_it_be(:aimed_for_deletion_project) { create(:project, :public, marked_for_deletion_at: 2.days.ago, pending_delete: false) } let_it_be(:aimed_for_deletion_project) { create(:project, :public, marked_for_deletion_at: 2.days.ago, pending_delete: false) }
let_it_be(:deleted_project) { create(:project, :public, marked_for_deletion_at: 1.month.ago, pending_delete: true) } let_it_be(:pending_deletion_project) { create(:project, :public, marked_for_deletion_at: 1.month.ago, pending_delete: true) }
it { is_expected.to contain_exactly(aimed_for_deletion_project) } it { is_expected.to contain_exactly(aimed_for_deletion_project) }
end end
context 'filter by not aimed for deletion' do
let_it_be(:params) { { not_aimed_for_deletion: true } }
let_it_be(:aimed_for_deletion_project) { create(:project, :public, marked_for_deletion_at: 2.days.ago, pending_delete: false) }
let_it_be(:pending_deletion_project) { create(:project, :public, marked_for_deletion_at: 1.month.ago, pending_delete: true) }
it { is_expected.to contain_exactly(ultimate_project, ultimate_project2, premium_project, no_plan_project) }
end
private private
def create_project(plan) def create_project(plan)
......
...@@ -97,14 +97,18 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do ...@@ -97,14 +97,18 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do
subject { get :starred, format: :json } subject { get :starred, format: :json }
let(:projects) { create_list(:project, 2, creator: user) } let(:projects) { create_list(:project, 2, creator: user) }
let(:aimed_for_deletion_project) { create_list(:project, 2, :archived, creator: user, marked_for_deletion_at: 3.days.ago) }
before do before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
projects.each do |project| projects.each do |project|
project.add_developer(user) project.add_developer(user)
create(:users_star_project, project_id: project.id, user_id: user.id) create(:users_star_project, project_id: project.id, user_id: user.id)
end end
aimed_for_deletion_project.each do |project|
project.add_developer(user)
create(:users_star_project, project_id: project.id, user_id: user.id)
end
end end
it 'returns success' do it 'returns success' do
...@@ -113,12 +117,24 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do ...@@ -113,12 +117,24 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
context "pagination" do
before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
end
it 'paginates the records' do it 'paginates the records' do
subject subject
expect(assigns(:projects).count).to eq(1) expect(assigns(:projects).count).to eq(1)
end end
end end
it 'does not include projects aimed for deletion' do
subject
expect(assigns(:projects).count).to eq(2)
end
end
end end
context 'atom requests' do context 'atom requests' do
......
...@@ -73,6 +73,24 @@ RSpec.describe Explore::ProjectsController do ...@@ -73,6 +73,24 @@ RSpec.describe Explore::ProjectsController do
expect(assigns(:projects)).to eq [project1, project2] expect(assigns(:projects)).to eq [project1, project2]
end end
end end
context 'projects aimed for deletion' do
let(:project1) { create(:project, :public, updated_at: 3.days.ago) }
let(:project2) { create(:project, :public, updated_at: 1.day.ago) }
let(:aimed_for_deletion_project) { create(:project, :public, :archived, updated_at: 2.days.ago, marked_for_deletion_at: 2.days.ago) }
before do
create(:trending_project, project: project1)
create(:trending_project, project: project2)
create(:trending_project, project: aimed_for_deletion_project)
end
it 'does not list projects aimed for deletion' do
get :trending
expect(assigns(:projects)).to eq [project2, project1]
end
end
end end
describe 'GET #topic' do describe 'GET #topic' do
......
...@@ -68,6 +68,12 @@ RSpec.describe GroupDescendantsFinder do ...@@ -68,6 +68,12 @@ RSpec.describe GroupDescendantsFinder do
expect(finder.execute).to be_empty expect(finder.execute).to be_empty
end end
it 'does not include projects aimed for deletion' do
_project_aimed_for_deletion = create(:project, :archived, marked_for_deletion_at: 2.days.ago, pending_delete: false)
expect(finder.execute).to be_empty
end
context 'with a filter' do context 'with a filter' do
let(:params) { { filter: 'test' } } let(:params) { { filter: 'test' } }
......
...@@ -3602,13 +3602,16 @@ RSpec.describe User do ...@@ -3602,13 +3602,16 @@ RSpec.describe User do
let!(:project1) { create(:project) } let!(:project1) { create(:project) }
let!(:project2) { fork_project(project3) } let!(:project2) { fork_project(project3) }
let!(:project3) { create(:project) } let!(:project3) { create(:project) }
let!(:project_aimed_for_deletion) { create(:project, marked_for_deletion_at: 2.days.ago, pending_delete: false) }
let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) } let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) }
let!(:push_event) { create(:push_event, project: project1, author: subject) } let!(:push_event) { create(:push_event, project: project1, author: subject) }
let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) } let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) }
let!(:merge_event_2) { create(:event, :created, project: project_aimed_for_deletion, target: merge_request, author: subject) }
before do before do
project1.add_maintainer(subject) project1.add_maintainer(subject)
project2.add_maintainer(subject) project2.add_maintainer(subject)
project_aimed_for_deletion.add_maintainer(subject)
end end
it 'includes IDs for projects the user has pushed to' do it 'includes IDs for projects the user has pushed to' do
...@@ -3622,6 +3625,10 @@ RSpec.describe User do ...@@ -3622,6 +3625,10 @@ RSpec.describe User do
it "doesn't include IDs for unrelated projects" do it "doesn't include IDs for unrelated projects" do
expect(subject.contributed_projects).not_to include(project2) expect(subject.contributed_projects).not_to include(project2)
end end
it "doesn't include projects aimed for deletion" do
expect(subject.contributed_projects).not_to include(project_aimed_for_deletion)
end
end end
describe '#fork_of' do describe '#fork_of' do
......
...@@ -506,6 +506,7 @@ RSpec.describe UsersController do ...@@ -506,6 +506,7 @@ RSpec.describe UsersController do
describe 'GET #contributed' do describe 'GET #contributed' do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:aimed_for_deletion_project) { create(:project, :public, :archived, marked_for_deletion_at: 3.days.ago) }
subject do subject do
get user_contributed_projects_url author.username, format: format get user_contributed_projects_url author.username, format: format
...@@ -516,7 +517,10 @@ RSpec.describe UsersController do ...@@ -516,7 +517,10 @@ RSpec.describe UsersController do
project.add_developer(public_user) project.add_developer(public_user)
project.add_developer(private_user) project.add_developer(private_user)
aimed_for_deletion_project.add_developer(public_user)
aimed_for_deletion_project.add_developer(private_user)
create(:push_event, project: project, author: author) create(:push_event, project: project, author: author)
create(:push_event, project: aimed_for_deletion_project, author: author)
subject subject
end end
...@@ -526,6 +530,11 @@ RSpec.describe UsersController do ...@@ -526,6 +530,11 @@ RSpec.describe UsersController do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.body).not_to be_empty expect(response.body).not_to be_empty
end end
it 'does not list projects aimed for deletion' do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:contributed_projects)).to eq([project])
end
end end
%i(html json).each do |format| %i(html json).each do |format|
...@@ -557,6 +566,7 @@ RSpec.describe UsersController do ...@@ -557,6 +566,7 @@ RSpec.describe UsersController do
describe 'GET #starred' do describe 'GET #starred' do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:aimed_for_deletion_project) { create(:project, :public, :archived, marked_for_deletion_at: 3.days.ago) }
subject do subject do
get user_starred_projects_url author.username, format: format get user_starred_projects_url author.username, format: format
...@@ -574,6 +584,11 @@ RSpec.describe UsersController do ...@@ -574,6 +584,11 @@ RSpec.describe UsersController do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.body).not_to be_empty expect(response.body).not_to be_empty
end end
it 'does not list projects aimed for deletion' do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:starred_projects)).to eq([project])
end
end end
%i(html json).each do |format| %i(html json).each do |format|
......
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