Page MenuHomePhorge

D25772.1726873928.diff
No OneTemporary

D25772.1726873928.diff

diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -748,9 +748,75 @@
$slug->delete();
}
+ // Destroy my milestones because they cannot live without me.
+ // Do not use PhabricatorProjectQuery to avoid a circular dependency,
+ // and, to do not have a load silent fail, since these milestones do not
+ // have their parent anymore.
+ $milestones = id(new self())
+ ->loadAllWhere('parentProjectPHID = %s AND milestoneNumber IS NOT NULL',
+ $this->getPHID());
+ foreach ($milestones as $milestone) {
+ $milestone->attachParentProject($this);
+ $engine->destroyObject($milestone);
+ }
+
+ // Update my children to eventually fix holes in the tree.
+ $this->onDestroyTouchChildren(true);
+
+ // After the tree is fixed, update my parent hasSubProjects field.
+ if ($this->getParentProject()) {
+ id(new PhabricatorProjectsMembershipIndexEngineExtension())
+ ->rematerialize($this->getParentProject());
+ }
+
$this->saveTransaction();
}
+ /**
+ * On destroy, eventually bubble up my direct children, to take my place.
+ * Refresh all remaining children, to consolidate depth, path key, etc.
+ */
+ private function onDestroyTouchChildren($close_my_hole) {
+ // Micro-optimization.
+ if (!$this->supportsSubprojects() && !$this->supportsMilestones()) {
+ return;
+ }
+
+ // Get direct sub-projects and milestones and their new desired parent.
+ // We must skip my direct milestones since they are under removal.
+ // Do not use PhabricatorProjectQuery to avoid a circular dependency.
+ $query_children = new self();
+ if ($close_my_hole) {
+ $desired_parent = $this->getParentProject();
+ $children = $query_children->loadAllWhere(
+ 'parentProjectPHID = %s AND milestoneNumber IS NULL',
+ $this->getPHID());
+ } else {
+ $desired_parent = $this;
+ $children = $query_children->loadAllWhere(
+ 'parentProjectPHID = %s',
+ $this->getPHID());
+ }
+
+ // The desired parent PHID for my children may become NULL,
+ // when we are closing my hole but my parent it's a root-project.
+ $desired_parent_phid = null;
+ if ($desired_parent) {
+ $desired_parent_phid = $desired_parent->getPHID();
+ }
+
+ // Eventually bubble up my direct children. Update the others.
+ foreach ($children as $child) {
+ $child->attachParentProject($desired_parent);
+ $child->setParentProjectPHID($desired_parent_phid);
+ $child->setProjectPathKey(null); // Force a new path key and depth.
+ $child->save();
+
+ // Descend the tree.
+ $child->onDestroyTouchChildren(false);
+ }
+ }
+
/* -( PhabricatorFulltextInterface )--------------------------------------- */
diff --git a/src/docs/user/userguide/projects.diviner b/src/docs/user/userguide/projects.diviner
--- a/src/docs/user/userguide/projects.diviner
+++ b/src/docs/user/userguide/projects.diviner
@@ -337,3 +337,89 @@
Form customization also provides a powerful tool for making many policy
management tasks easier (see @{article:User Guide: Customizing Forms}).
+
+Archiviation
+============
+
+Like most things in real life, sometime also a project tag or a milestone
+can become not useful anymore, maybe because they reached their deadline,
+maybe because their investor was actually a scam, maybe because your
+boss created a nonsense project by mistake with their faulty mouse, etc.
+
+In general, in most cases, we strongly recommend to archive projects instead
+of destroying them. First, because Phorge does not encourage killing life forms.
+Second, because keeping track of which colleagues worked on legacy projects
+is generally useful. Third, because the alternative is destroying projects
+from the command line, but destroying things is generally very scary,
+very unsafe, not recommended. In the other hand, archiviation is in
+general very stable, well-tested, safe, encouraged, reversible, and full of
+satisfaction. Some Phorge instances also start smelling of peach fragrances,
+after you archive your first project.
+
+People who can {nav icon=pencil,name=Edit} a project can also
+use the {nav icon=ban,name=Archive} action.
+
+Archived projects will generally avoid to distract you, but they will preserve
+their past glory. For example:
+
+- archived projects are de-prioritized from most search selections,
+ including the top search bar, including tag pickers, etc.
+- archived projects are unlisted from the active list at /project/query/active/
+- archived projects are generally kept where they had been placed, but are
+ generously de-colorized from their tag badges, or stroked
+- archived projects are muted, do not cause extra "watch" notifications
+
+All the following consequences are reversible. You can turn a project back
+to life anytime using the {nav icon=check,name=Activate project} action.
+
+If you need to hide a project from the eyes of your delicate coworkers,
+you can also evaluate changes in the project visibility, to show it only to
+you, or only to some coworkers that still have love for archived materials.
+
+If at this point we still haven't convinced you to archive your projects,
+enjoy the next scary section.
+
+Permanently Destroy
+===================
+
+Phorge is designed as a safe collaborative platform that rarely
+allows to permanently destroy things from the web interface. But...
+there are still uncommon circumstances were you may want to afford
+all the risks in the wild and not recommended world of
+@{article:Permanently Destroying Data}.
+
+What happens when you permanently destroy a project (including a milestone)
+using the command line:
+
+- the project is destroyed permanently, forever (unless you have a good backup)
+- all objects (such as tasks, repositories, etc.) to which you set visibility
+ restrictions like "visible to: members of THAT TAG" may immediately become
+ completely invisible from the web interface and API results
+- tagged stuff is generally preserved, including tasks, commits,
+ wiki documents, events, repositories, etc. and these objects will simply
+ be not associated anymore with that project tag (but will remain associated
+ with other tags, of course)
+- users that are members of the destroyed project are preserved but
+ they are unassigned from that project
+- watchers of the destroyed project are preserved but they may need to find
+ something else to look at
+- if the project has a workboard, that workboard is destroyed as well
+ (tasks in that workboard will be kept and will remain associated
+ with other workboards, of course)
+- if the project has direct milestones, these milestones are destroyed as well
+ (note that milestones are technically projects, so, read aloud this list
+ again to understand what will happen to these milestones, and to stuff
+ associated to these milestones, etc.)
+- if the project has a parent project, and if that parent will not have other
+ children projects anymore, that parent may be promoted to root-project again.
+ This means you will probably be able to directly edit the members of the
+ parent project, again.
+- if the project has sub-projects, all sub-projects and all their descendant
+ sub-projects will climb the tree depth by one level, to still have sense
+ and still be preserved. Grandchildren become children. Sons become parents,
+ etc. - a real mess for family photos.
+- you increase the risk of something totally unexpected happening, like, your
+ entire datacenter may be destroyed by a rebel fleet of Slugma Pokemons
+ out of recursion control.
+
+So, please consider just simply archiving projects instead of destroying them.

File Metadata

Mime Type
text/plain
Expires
Fri, Sep 20, 23:12 (21 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
893419
Default Alt Text
D25772.1726873928.diff (7 KB)

Event Timeline