3 final class PhabricatorRepositoryManagementUnpublishWorkflow
4 extends PhabricatorRepositoryManagementWorkflow
{
6 protected function didConstruct() {
10 '**unpublish** [__options__] __repository__')
13 'Unpublish all feed stories and notifications that a repository '.
14 'has generated. Keep expectations low; can not rewind time.'))
19 'help' => pht('Do not prompt for confirmation.'),
23 'help' => pht('Do not perform any writes.'),
26 'name' => 'repositories',
32 public function execute(PhutilArgumentParser
$args) {
33 $viewer = $this->getViewer();
34 $is_force = $args->getArg('force');
35 $is_dry_run = $args->getArg('dry-run');
37 $repositories = $this->loadLocalRepositories($args, 'repositories');
38 if (count($repositories) !== 1) {
39 throw new PhutilArgumentUsageException(
40 pht('Specify exactly one repository to unpublish.'));
42 $repository = head($repositories);
48 'This script will unpublish all feed stories and notifications '.
49 'which a repository generated during import. This action can not '.
53 'Permanently unpublish "%s"?',
54 $repository->getDisplayName());
55 if (!phutil_console_confirm($prompt)) {
56 throw new PhutilArgumentUsageException(
57 pht('User aborted workflow.'));
61 $commits = id(new DiffusionCommitQuery())
63 ->withRepositoryPHIDs(array($repository->getPHID()))
66 echo pht("Will unpublish %s commits.\n", count($commits));
68 foreach ($commits as $commit) {
69 $this->unpublishCommit($commit, $is_dry_run);
75 private function unpublishCommit(
76 PhabricatorRepositoryCommit
$commit,
78 $viewer = $this->getViewer();
83 'Unpublishing commit "%s".',
84 $commit->getMonogram()));
86 $stories = id(new PhabricatorFeedQuery())
88 ->withFilterPHIDs(array($commit->getPHID()))
95 'Found %s feed storie(s).',
99 $engine = new PhabricatorDestructionEngine();
100 foreach ($stories as $story) {
101 $story_data = $story->getStoryData();
102 $engine->destroyObject($story_data);
108 'Destroyed %s feed storie(s).',
114 PhabricatorObjectMentionsObjectEdgeType
::EDGECONST
=> true,
115 DiffusionCommitHasTaskEdgeType
::EDGECONST
=> true,
116 DiffusionCommitHasRevisionEdgeType
::EDGECONST
=> true,
117 DiffusionCommitRevertsCommitEdgeType
::EDGECONST
=> true,
120 $query = id(new PhabricatorEdgeQuery())
121 ->withSourcePHIDs(array($commit->getPHID()))
122 ->withEdgeTypes(array_keys($edge_types));
123 $edges = $query->execute();
125 foreach ($edges[$commit->getPHID()] as $type => $edge_list) {
126 foreach ($edge_list as $edge) {
132 'Commit "%s" has edge of type "%s" to object "%s".',
133 $commit->getMonogram(),
137 $object = id(new PhabricatorObjectQuery())
139 ->withPHIDs(array($dst))
142 if ($object instanceof PhabricatorApplicationTransactionInterface
) {
143 $this->unpublishEdgeTransaction(
154 private function unpublishEdgeTransaction(
157 PhabricatorApplicationTransactionInterface
$dst,
159 $viewer = $this->getViewer();
161 $query = PhabricatorApplicationTransactionQuery
::newQueryForObject($dst)
163 ->withObjectPHIDs(array($dst->getPHID()));
165 $xactions = id(clone $query)
166 ->withTransactionTypes(
168 PhabricatorTransactions
::TYPE_EDGE
,
172 $type_obj = PhabricatorEdgeType
::getByConstant($type);
173 $inverse_type = $type_obj->getInverseEdgeConstant();
175 $engine = new PhabricatorDestructionEngine();
176 foreach ($xactions as $xaction) {
177 $edge_type = $xaction->getMetadataValue('edge:type');
178 if ($edge_type != $inverse_type) {
179 // Some other type of edge was edited.
183 $record = PhabricatorEdgeChangeRecord
::newFromTransaction($xaction);
184 $changed = $record->getChangedPHIDs();
185 if ($changed !== array($src->getPHID())) {
186 // Affected objects were not just the object we're unpublishing.
193 'Found edge transaction "%s" on object "%s" for type "%s".',
199 $engine->destroyObject($xaction);
204 'Destroyed transaction "%s" on object "%s".',
210 if ($type === DiffusionCommitHasTaskEdgeType
::EDGECONST
) {
211 $xactions = id(clone $query)
212 ->withTransactionTypes(
214 ManiphestTaskStatusTransaction
::TRANSACTIONTYPE
,
219 foreach ($xactions as $xaction) {
220 $metadata = $xaction->getMetadata();
221 if (idx($metadata, 'commitPHID') === $src->getPHID()) {
225 'MANUAL Task "%s" was likely closed improperly by "%s".',
227 $src->getMonogram()));
233 if ($type === DiffusionCommitHasRevisionEdgeType
::EDGECONST
) {
234 $xactions = id(clone $query)
235 ->withTransactionTypes(
237 DifferentialRevisionCloseTransaction
::TRANSACTIONTYPE
,
242 foreach ($xactions as $xaction) {
243 $metadata = $xaction->getMetadata();
244 if (idx($metadata, 'commitPHID') === $src->getPHID()) {
248 'MANUAL Revision "%s" was likely closed improperly by "%s".',
250 $src->getMonogram()));
257 id(new PhabricatorEdgeEditor())
258 ->removeEdge($src->getPHID(), $type, $dst->getPHID())
263 'Destroyed edge of type "%s" between "%s" and "%s".',