Projects: improve quality of destroy workflow
Summary:
When you permanently destroy a specific project from the command line, the following
additional good things now happen:
- all direct milestones are removed too (since they cannot live alone, and they cannot be just "moved" to the parent project since their resulting sequence would have no sense)
- closing T15913: direct milestones are not orphan, broken, invisible anymore, do not become junk in the database anymore, do not cause project query overhead anymore
- all children projects emerge like cute bubbles by one level
- closing T15918: children projects are not orphan, broken, invisible anymore
- the parent project is eventually restored as "without sub-projects", so, joinable again
- closing T15697: the parent project has not bugged memberships anymore
This change will only affect future usages of the destroy workflow on a project (or root-project or sub-project), that is, this command line workflow:
./bin/remove destroy PHID-OF-YOUR-PROJECT-TO-BE-DESTROYED
## Limitations
This change has nothing to do with the action "Archive" on projects (btw, archiving still works and it's still very recommended).
This change does not try to improve the destruction of a specific milestone (still not recommended because milestones are in sequence and more discussion is needed to improve this corner case of the destruction of a single very specific milestone, btw it works).
This change does not try to improve the destruction of a specific workboard (btw, a workboard does not really exist, it's just a flag in the project).
## Example initial situation
```
Project A
[projectDepth: 0]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project B
[projectDepth: 1]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project C
[hasSubprojects: 0]
[projectDepth: 2]
[members: foo, bar]
> Milestone C.1
[projectDepth: 3]
```
Situation after destroying only project A:
```
Project B
[projectDepth: 0]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project C
[projectDepth: 1]
[hasSubprojects: 0]
[members: foo, bar]
> Milestone C.1
[projectDepth: 2]
```
Situation after destroying only project B:
```
Project A
[projectDepth: 0]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project C
[projectDepth: 1]
[hasSubprojects: 0]
[members: foo, bar]
> Milestone C.1
[projectDepth: 2]
```
Situation after destroying only project C:
```
Project A
[projectDepth: 0]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project B
[projectDepth: 1]
[hasSubprojects: 0]
[members: foo, bar]
```
Situation after destroying only milestone C.1:
```
Project A
[projectDepth: 0]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project B
[projectDepth: 1]
[hasSubprojects: 1]
[members: *automatic*, foo, bar]
> Project C
[hasSubprojects: 0]
[projectDepth: 2]
[members: foo, bar]
```
Closes T15697
Closes T15913
Closes T15918
Closes T16043
Test Plan:
Run multiple times the destroy workflow under every imaginable case,
to violently destroy a projects tree, leaf by leaf. We suggest to run it
with the trace option. Example:
./bin/remove destroy --trace PHID-PROJ-s0met1ng
To run the above workflow multiple times, you may appreciate a dump:
./bin/storage dump | gzip > dump.sql.gz
So you can easily restore it whenever you want:
zcat dump.sql.gz | ./bin/storage shell
- Delete simple milestone
- create a new simple project "A" with milestone "M" and delete "M"
- deletion still works on milestone "M"
- Delete simple project
- create a new simple project "A" with a workboard and destroy "A":
- deletion still works on project "A"
- workboard is still not accessible
- if there were tasks, they are still there but without tag "A"
- Delete project with milestone (T15913)
- create a new project "A" with a milestone "B" and delete "A"
- deletion still works on project "A"
- milestone "B" is finally nuked from the database
and you do not see it anymore in the phabricator_project table
- Delete a project with sub-projects (T15918)
- create a new project "A" with a sub-project called "B" and delete "A"
- deletion still works on project "A"
- project "B" becomes a root-project and it has depth "0" again
and it's usable, instead of having it borked with "You Shall Not Pass"
- Delete a sub-project (T15697)
- create a new project "A" with a sub-project called "B" and delete "B"
- deletion still works on project "B"
- project "A" is usable again like "B" never existed, so you can
change memberships and all the things, instead of having it borked
If you don't have enough time to test this, just enjoy the new unit tests covering the destroy process (T16043):
arc unit src/applications/project/storage/PhabricatorProject.php
In particular, in the unit test results, check the new green light about this method:
PhabricatorProjectCoreTestCase::testProjectDestroy
Reviewers: O1 Blessed Committers, mainframe98
Reviewed By: O1 Blessed Committers, mainframe98
Subscribers: waldyrious, mainframe98, tobiaswiese, Matthew, Cigaryno
Tags: #projects
Maniphest Tasks: T15913, T15697, T15918, T16043
Differential Revision: https://we.phorge.it/D25772