protected function buildCustomEditFields($object) { $paths_help = pht(<<<EOTEXT When updating the paths for a package, pass a list of dictionaries like this as the `value` for the transaction: ```lang=json, name="Example Paths Value" [ { "repositoryPHID": "PHID-REPO-1234", "path": "/path/to/directory/", "excluded": false }, { "repositoryPHID": "PHID-REPO-1234", "path": "/another/example/path/", "excluded": false } ] ``` This transaction will set the paths to the list you provide, overwriting any previous paths. Generally, you will call `owners.search` first to get a list of current paths (which are provided in the same format), make changes, then update them by applying a transaction of this type. EOTEXT ); $autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); $autoreview_map = ipull($autoreview_map, 'name'); $dominion_map = PhabricatorOwnersPackage::getDominionOptionsMap(); $dominion_map = ipull($dominion_map, 'name'); return array(id(new PhabricatorTextEditField())->setKey('name')->setLabel(pht('Name'))->setDescription(pht('Name of the package.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_NAME)->setIsRequired(true)->setValue($object->getName()), id(new PhabricatorDatasourceEditField())->setKey('owners')->setLabel(pht('Owners'))->setDescription(pht('Users and projects which own the package.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_OWNERS)->setDatasource(new PhabricatorProjectOrUserDatasource())->setIsCopyable(true)->setValue($object->getOwnerPHIDs()), id(new PhabricatorSelectEditField())->setKey('dominion')->setLabel(pht('Dominion'))->setDescription(pht('Change package dominion rules.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_DOMINION)->setIsCopyable(true)->setValue($object->getDominion())->setOptions($dominion_map), id(new PhabricatorSelectEditField())->setKey('autoReview')->setLabel(pht('Auto Review'))->setDescription(pht('Automatically trigger reviews for commits affecting files in ' . 'this package.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW)->setIsCopyable(true)->setValue($object->getAutoReview())->setOptions($autoreview_map), id(new PhabricatorSelectEditField())->setKey('auditing')->setLabel(pht('Auditing'))->setDescription(pht('Automatically trigger audits for commits affecting files in ' . 'this package.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_AUDITING)->setIsCopyable(true)->setValue($object->getAuditingEnabled())->setOptions(array('' => pht('Disabled'), '1' => pht('Enabled'))), id(new PhabricatorRemarkupEditField())->setKey('description')->setLabel(pht('Description'))->setDescription(pht('Human-readable description of the package.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION)->setValue($object->getDescription()), id(new PhabricatorSelectEditField())->setKey('status')->setLabel(pht('Status'))->setDescription(pht('Archive or enable the package.'))->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_STATUS)->setIsConduitOnly(true)->setValue($object->getStatus())->setOptions($object->getStatusNameMap()), id(new PhabricatorConduitEditField())->setKey('paths.set')->setLabel(pht('Paths'))->setIsConduitOnly(true)->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_PATHS)->setConduitDescription(pht('Overwrite existing package paths with new paths.'))->setConduitTypeDescription(pht('List of dictionaries, each describing a path.'))->setConduitDocumentation($paths_help)); }
public function getTitle() { $map = PhabricatorOwnersPackage::getDominionOptionsMap(); $map = ipull($map, 'short'); $old = $this->getOldValue(); $new = $this->getNewValue(); $old = idx($map, $old, $old); $new = idx($map, $new, $new); return pht('%s adjusted package dominion rules from %s to %s.', $this->renderAuthor(), $this->renderValue($old), $this->renderValue($new)); }
private function buildPackageDetailView(PhabricatorOwnersPackage $package, PhabricatorCustomFieldList $field_list) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView())->setUser($viewer); $owners = $package->getOwners(); if ($owners) { $owner_list = $viewer->renderHandleList(mpull($owners, 'getUserPHID')); } else { $owner_list = phutil_tag('em', array(), pht('None')); } $view->addProperty(pht('Owners'), $owner_list); $dominion = $package->getDominion(); $dominion_map = PhabricatorOwnersPackage::getDominionOptionsMap(); $spec = idx($dominion_map, $dominion, array()); $name = idx($spec, 'short', $dominion); $view->addProperty(pht('Dominion'), $name); $auto = $package->getAutoReview(); $autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); $spec = idx($autoreview_map, $auto, array()); $name = idx($spec, 'name', $auto); $view->addProperty(pht('Auto Review'), $name); if ($package->getAuditingEnabled()) { $auditing = pht('Enabled'); } else { $auditing = pht('Disabled'); } $view->addProperty(pht('Auditing'), $auditing); $description = $package->getDescription(); if (strlen($description)) { $description = new PHUIRemarkupView($viewer, $description); $view->addSectionHeader(pht('Description')); $view->addTextContent($description); } $field_list->appendFieldsToPropertyList($package, $viewer, $view); return $view; }
public function getTitle() { $old = $this->getOldValue(); $new = $this->getNewValue(); $author_phid = $this->getAuthorPHID(); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CREATE: return pht('%s created this package.', $this->renderHandleLink($author_phid)); case self::TYPE_NAME: if ($old === null) { return pht('%s created this package.', $this->renderHandleLink($author_phid)); } else { return pht('%s renamed this package from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } case self::TYPE_OWNERS: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && !$rem) { return pht('%s added %s owner(s): %s.', $this->renderHandleLink($author_phid), count($add), $this->renderHandleList($add)); } else { if ($rem && !$add) { return pht('%s removed %s owner(s): %s.', $this->renderHandleLink($author_phid), count($rem), $this->renderHandleList($rem)); } else { return pht('%s changed %s package owner(s), added %s: %s; removed %s: %s.', $this->renderHandleLink($author_phid), count($add) + count($rem), count($add), $this->renderHandleList($add), count($rem), $this->renderHandleList($rem)); } } case self::TYPE_AUDITING: if ($new) { return pht('%s enabled auditing for this package.', $this->renderHandleLink($author_phid)); } else { return pht('%s disabled auditing for this package.', $this->renderHandleLink($author_phid)); } case self::TYPE_DESCRIPTION: return pht('%s updated the description for this package.', $this->renderHandleLink($author_phid)); case self::TYPE_PATHS: // TODO: Flesh this out. return pht('%s updated paths for this package.', $this->renderHandleLink($author_phid)); case self::TYPE_STATUS: if ($new == PhabricatorOwnersPackage::STATUS_ACTIVE) { return pht('%s activated this package.', $this->renderHandleLink($author_phid)); } else { if ($new == PhabricatorOwnersPackage::STATUS_ARCHIVED) { return pht('%s archived this package.', $this->renderHandleLink($author_phid)); } } case self::TYPE_AUTOREVIEW: $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); $map = ipull($map, 'name'); $old = idx($map, $old, $old); $new = idx($map, $new, $new); return pht('%s adjusted autoreview from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); case self::TYPE_DOMINION: $map = PhabricatorOwnersPackage::getDominionOptionsMap(); $map = ipull($map, 'short'); $old = idx($map, $old, $old); $new = idx($map, $new, $new); return pht('%s adjusted package dominion rules from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } return parent::getTitle(); }
protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { case PhabricatorOwnersPackageTransaction::TYPE_NAME: $missing = $this->validateIsEmptyTextField($object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Package name is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } foreach ($xactions as $xaction) { $new = $xaction->getNewValue(); if (preg_match('([,!])', $new)) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Package names may not contain commas (",") or exclamation ' . 'marks ("!"). These characters are ambiguous when package ' . 'names are parsed from the command line.'), $xaction); } } break; case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW: $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); foreach ($xactions as $xaction) { $new = $xaction->getNewValue(); if (empty($map[$new])) { $valid = array_keys($map); $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Autoreview setting "%s" is not valid. ' . 'Valid settings are: %s.', $new, implode(', ', $valid)), $xaction); } } break; case PhabricatorOwnersPackageTransaction::TYPE_DOMINION: $map = PhabricatorOwnersPackage::getDominionOptionsMap(); foreach ($xactions as $xaction) { $new = $xaction->getNewValue(); if (empty($map[$new])) { $valid = array_keys($map); $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Dominion setting "%s" is not valid. ' . 'Valid settings are: %s.', $new, implode(', ', $valid)), $xaction); } } break; case PhabricatorOwnersPackageTransaction::TYPE_PATHS: if (!$xactions) { continue; } $old = mpull($object->getPaths(), 'getRef'); foreach ($xactions as $xaction) { $new = $xaction->getNewValue(); // Check that we have a list of paths. if (!is_array($new)) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Path specification must be a list of paths.'), $xaction); continue; } // Check that each item in the list is formatted properly. $type_exception = null; foreach ($new as $key => $value) { try { PhutilTypeSpec::checkMap($value, array('repositoryPHID' => 'string', 'path' => 'string', 'excluded' => 'optional wild')); } catch (PhutilTypeCheckException $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Path specification list contains invalid value ' . 'in key "%s": %s.', $key, $ex->getMessage()), $xaction); $type_exception = $ex; } } if ($type_exception) { continue; } // Check that any new paths reference legitimate repositories which // the viewer has permission to see. list($rem, $add) = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); if ($add) { $repository_phids = ipull($add, 'repositoryPHID'); $repositories = id(new PhabricatorRepositoryQuery())->setViewer($this->getActor())->withPHIDs($repository_phids)->execute(); $repositories = mpull($repositories, null, 'getPHID'); foreach ($add as $ref) { $repository_phid = $ref['repositoryPHID']; if (isset($repositories[$repository_phid])) { continue; } $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Path specification list references repository PHID "%s", ' . 'but that is not a valid, visible repository.', $repository_phid)); } } } break; } return $errors; }