Commit 17528418 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Allow immediate deletion of projects

Allow users to immediately delete a project that is scheduled for
deletion.

Changelog: added
EE: true
parent e20771af
......@@ -364,13 +364,18 @@ namespace if needed.
#### Delete a project
NOTE:
Only project Owners and administrators have [permissions](../../permissions.md#project-members-permissions) to delete a project.
You can mark a project to be deleted.
Prerequisite:
- You must have at least the Owner role for a project.
To delete a project:
1. Navigate to your project, and select **Settings > General > Advanced**.
1. In the "Delete project" section, click the **Delete project** button.
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Advanced**.
1. In the "Delete project" section, select **Delete project**.
1. Confirm the action when asked to.
This action deletes a project including all associated resources (issues, merge requests, and so on).
......@@ -385,6 +390,28 @@ WARNING:
The default behavior of [delayed project deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/32935) in GitLab 12.6 was changed to
[Immediate deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) in GitLab 13.2.
#### Delete a project immediately **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/191367) in GitLab 14.1.
If you don't want to wait, you can delete a project immediately.
Prerequisites:
- You must have at least the Owner role for a project.
- You have [marked the project for deletion](#delete-a-project).
To immediately delete a project marked for deletion:
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Advanced**.
1. In the "Permanently delete project" section, select **Delete project**.
1. Confirm the action when asked to.
Your project, its repository, and all related resources, including issues and merge requests,
are deleted.
#### Restore a project **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32935) in GitLab 12.6.
......
......@@ -36,6 +36,8 @@ module EE
override :destroy
def destroy
return super unless project.adjourned_deletion?
return super if project.marked_for_deletion? && params[:permanently_delete].present?
return access_denied! unless can?(current_user, :remove_project, project)
result = ::Projects::MarkForDeletionService.new(project, current_user, {}).execute
......
......@@ -22,4 +22,5 @@
#js-project-delete-button{ data: { form_path: project_path(project), confirm_phrase: project.path } }
- else
= render 'projects/settings/restore', project: project
= render 'projects/settings/permanently_delete', project: project
.sub-section
%h4.danger-title= _('Permanently delete project')
%p
%strong= _('Deleting the project will delete its repository and all related resources including issues, merge requests, etc.')
%p= permanent_delete_message(project)
%p
%strong= _('Are you ABSOLUTELY SURE you wish to delete this project?')
#js-project-delete-button{ data: { form_path: project_path(project, permanently_delete: true), confirm_phrase: project.path } }
......@@ -2,12 +2,12 @@
- date = permanent_deletion_date(project.marked_for_deletion_at)
.sub-section
%h4.danger-title= _('Restore project')
%h4= _('Restore project')
%p
%strong= _('This project will be deleted on %{date}') %{ date: date }
%p
= _("Restoring the project will prevent the project from being removed on this date and restore people's ability to make changes to it.")
= _("The repository can be committed to, and issues, comments and other entities can be created.")
%strong= _('Only active this projects shows up in the search and on the dashboard.')
%strong= _('Only active projects show up in the search and on the dashboard.')
= link_to _('Restore project'), namespace_project_restore_path(project.namespace, project),
method: :post, class: "gl-button btn btn-danger"
method: :post, class: "gl-button btn"
......@@ -749,6 +749,34 @@ RSpec.describe ProjectsController do
expect(response).to redirect_to(dashboard_projects_path)
end
end
context 'when project is already marked for deletion' do
let(:project) { create(:project, group: group, marked_for_deletion_at: Date.current) }
context 'when permanently_delete param is set' do
it 'deletes project right away' do
expect(ProjectDestroyWorker).to receive(:perform_async)
delete :destroy, params: { namespace_id: project.namespace, id: project, permanently_delete: true }
expect(project.reload.pending_delete).to eq(true)
expect(response).to have_gitlab_http_status(:found)
expect(response).to redirect_to(dashboard_projects_path)
end
end
context 'when permanently_delete param is not set' do
it 'does nothing' do
expect(ProjectDestroyWorker).not_to receive(:perform_async)
delete :destroy, params: { namespace_id: project.namespace, id: project }
expect(project.reload.pending_delete).to eq(false)
expect(response).to have_gitlab_http_status(:found)
expect(response).to redirect_to(project_path(project))
end
end
end
end
context 'when feature is disabled for group' do
......
......@@ -2,8 +2,8 @@
require 'spec_helper'
RSpec.describe 'Project', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/222234' do
describe 'when creating from group template' do
RSpec.describe 'Project', :js do
describe 'when creating from group template', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/222234' do
let(:user) { create(:user) }
let(:group) { create(:group, name: 'parent-group') }
let(:template_subgroup) { create(:group, parent: group, name: 'template-subgroup') }
......@@ -35,4 +35,29 @@ RSpec.describe 'Project', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab
expect(find('.js-select-namespace')).to have_content other_subgroup.name
end
end
describe 'immediately deleting a project marked for deletion' do
let(:project) { create(:project, marked_for_deletion_at: Date.current) }
let(:user) { project.owner }
before do
stub_licensed_features(adjourned_deletion_for_projects_and_groups: true)
sign_in user
visit edit_project_path(project)
end
it 'deletes the project immediately', :sidekiq_inline do
expect { remove_with_confirm('Delete project', project.path, 'Yes, delete project') }.to change { Project.count }.by(-1)
expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted."
expect(Project.all.count).to be_zero
end
def remove_with_confirm(button_text, confirm_with, confirm_button_text = 'Confirm')
click_button button_text
fill_in 'confirm_name_input', with: confirm_with
click_button confirm_button_text
end
end
end
......@@ -23063,7 +23063,7 @@ msgstr ""
msgid "Only Project Members"
msgstr ""
msgid "Only active this projects shows up in the search and on the dashboard."
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
msgid "Only admins can delete project"
......@@ -23909,6 +23909,9 @@ msgstr ""
msgid "PerformanceBar|Trace"
msgstr ""
msgid "Permanently delete project"
msgstr ""
msgid "Permissions"
msgstr ""
......
......@@ -256,7 +256,7 @@ RSpec.describe 'Project' do
expect(page).to have_selector '#confirm_name_input:focus'
end
it 'deletes a project', :sidekiq_might_not_need_inline do
it 'deletes a project', :sidekiq_inline do
expect { remove_with_confirm('Delete project', project.path, 'Yes, delete project') }.to change { Project.count }.by(-1)
expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted."
expect(Project.all.count).to be_zero
......
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