Page MenuHomePhorge

D25772.1742698281.diff
No OneTemporary

D25772.1742698281.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,126 @@
Form customization also provides a powerful tool for making many policy
management tasks easier (see @{article:User Guide: Customizing Forms}).
+
+Archiving
+=========
+
+Phorge supports the destroy (unsafe) and the archive (safe) of projects.
+
+Archiving a project (or archiving a milestone - since milestones are projects)
+is very recommended: you are encouraged in archiving a project when it stopped
+being useful, when the project reached its deadline, or when its investor was
+a scam. You might be surprised how useful it is to know which colleagues have
+worked on a certain very old archived project, which fortunately somebody
+decided to archive rather than violently destroy.
+Archiving still has sense when your boss created a nonsense project about
+how-to integrate Phorge with Doom, but now would like to hide all traces...
+still, please desist from looking for destruction, and evaluate archiving it,
+and not only for the glory of the internal documentation in your organization.
+
+The {nav icon=ban,name=Archive} action is visible to all people who
+can {nav icon=pencil,name=Edit} a project. As usual in Phorge,
+there is a confirmation dialog.
+
+After you confirm to archive a project, these things will happen:
+
+- in general, the archived project will avoid to distract people,
+ still preserving its past glory.
+- whatever mentions the tag or its hashtag, the related badge is generously
+ de-colorized or struck-through.
+- the archived project is unlisted from the active list at
+ [ /project/query/active/ ]( /project/query/active/ )
+- the archived project is de-prioritized from most search results and selectors,
+ including the top search bar, the tag pickers, etc.
+- the archived project is muted, and do not cause "watch" notifications.
+- who triggered this action is logged in the recent actions.
+
+All these consequences are reversible. You can bring a project back
+to life anytime using the {nav icon=check,name=Activate project} action.
+
+After archiving a project, all tagged objects, tagged tasks, etc. will be
+intentionally kept as-is. In particular, on tagged objects is not
+enforced any special read-only policy. This has sense if you have paid
+attention to "Policies In Depth". In short, an object can have so many tags,
+and if a specific team group closed its operations does not mean that others
+should stop working on all their tagged stuff, etc.
+
+After you presented "how amazing is Phorge about archiving projects" and
+after you distributed stickers about `#JustArchive` to all coworkers,
+it's a classic that somebody still want to "just remove the project" or
+"make it go away" or "run obliviate", etc.
+In these cases where "more censorship" is needed, you can evaluate an
+additional change in the visibility settings of that project. For example,
+the very limited visibility "show only to me" makes the project effectively
+invisible to others. Mastering the visibility policies helps a lot in making
+sure your cleanup requests are managed professionally and in a secure way,
+still allowing future auditing, when needed.
+
+At this point, if you still haven't convinced everyone to archive a specific
+project, explore the next scary and unsafe section about permanently destroying.
+
+Permanently Destroying
+======================
+
+Phorge is designed as a safe collaborative platform that rarely
+requires @{article:Permanently Destroying Data}.
+
+If you have read that article, and if you have done a backup, and if
+you have access the command line, and if you still want to permanently
+destroy a project (or a milestone), these will be the consequences:
+
+- the project is destroyed permanently from the database, forever
+ (unless you have a good backup and sufficient recover skills)
+- all objects, including tasks, repositories, wiki documents, calendars,
+ secrets, other projects, etc. to which you set visibility restrictions
+ involving that project (example: "visible to project members"),
+ these objects will be broken, and everyone will be locked out of them.
+ It means these objects will become completely invisible from the web
+ interface and API results.
+ You still have margin to recover from these particular policy problems,
+ reading the @{article:User Guide: Unlocking Objects}.
+- tagged items are generally preserved, including tasks, commits,
+ wiki documents, calendar events, repositories, etc. and these objects
+ will simply not be associated anymore with that project tag
+ (but will remain associated with other tags, of course).
+- users that are members or watchers of the destroyed project will be
+ kept in your Phorge but unassigned from that project.
+ Watchers might go crazy until they find something else to watch.
+- comments and texts wrote by users will be preserved even if they were
+ mentioning your `#project` but that hashtag will not render a link.
+ You will still be able to add that hashtag in another project,
+ to revive these links.
+- if the project has a workboard, that workboard is destroyed as well
+ (tasks in that workboard will always be kept and will remain associated
+ with other workboards, in case).
+- if the project has direct milestones, these milestones are destroyed as well
+ (note that milestones are technically projects, so, read this list
+ again aloud to understand what will happen to these milestones, and to items
+ associated to these milestones, etc.)
+- if the project has a parent project, and if that parent has no other child
+ projects anymore, that parent can be promoted to root-project again.
+ This means the members of the parent project will be editable 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 fill the hole
+ you caused. Grandchildren become children, sons become parents,
+ etc. - a real mess for family photos.
+- you increase the risk of something completely unexpected happening,
+ such as the destruction of your entire datacenter by our
+ Slugma Pokemons out of recursion control.
+
+To permanently destroy a project, you will need to execute a command like this,
+from the root directory of the Phorge repository on your server:
+
+```
+./bin/remove destroy PHID-PROJ-abcdef123456
+```
+
+The command needs the "PHID" code of the project.
+Every project has a PHID and it can be easily retrieved in multiple ways,
+including the {nav icon=cog,name=Manage} menu of that project, hovering
+the cursor on the {nav icon=flag,name=Flag For Later} feature.
+
+This command requires a manual confirmation. Before proceeding,
+take the disclaimer seriously and read again the previous section about
+archiving projects (safe), instead of permanently destroying them (unsafe),
+to eventually change your mind.

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 23, 02:51 (19 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1192616
Default Alt Text
D25772.1742698281.diff (9 KB)

Event Timeline