private function buildPackagePropertyView(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); 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'), PHUIPropertyListView::ICON_SUMMARY); $view->addTextContent($description); } $view->invokeWillRenderEvent(); $field_list->appendFieldsToPropertyList($package, $viewer, $view); return $view; }
private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package) { $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID()); $reasons = array(); if ($data->getCommitDetail('vsDiff')) { $reasons[] = pht('Changed After Revision Was Accepted'); } $commit_author_phid = $data->getCommitDetail('authorPHID'); if (!$commit_author_phid) { $reasons[] = pht('Commit Author Not Recognized'); } $revision_id = $data->getCommitDetail('differential.revisionID'); $revision_author_phid = null; $commit_reviewedby_phid = null; if ($revision_id) { $revision = id(new DifferentialRevisionQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIDs(array($revision_id))->executeOne(); if ($revision) { $revision_author_phid = $revision->getAuthorPHID(); $commit_reviewedby_phid = $data->getCommitDetail('reviewerPHID'); if ($revision_author_phid !== $commit_author_phid) { $reasons[] = pht('Author Not Matching with Revision'); } } else { $reasons[] = pht('Revision Not Found'); } } else { $reasons[] = pht('No Revision Specified'); } $owners_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(array($package->getID())); if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $commit_reviewedby_phid && in_array($commit_reviewedby_phid, $owners_phids))) { $reasons[] = pht('Owners Not Involved'); } return $reasons; }
private static function loadPackagesForPaths(PhabricatorRepository $repository, array $paths, $limit = 0) { $package = new PhabricatorOwnersPackage(); $path = new PhabricatorOwnersPath(); $conn = $package->establishConnection('r'); $repository_clause = qsprintf($conn, 'AND p.repositoryPHID = %s', $repository->getPHID()); $limit_clause = ''; if (!empty($limit)) { $limit_clause = qsprintf($conn, 'LIMIT %d', $limit); } $data = queryfx_all($conn, 'SELECT pkg.id FROM %T pkg JOIN %T p ON p.packageID = pkg.id WHERE p.path IN (%Ls) %Q ORDER BY LENGTH(p.path) DESC %Q', $package->getTableName(), $path->getTableName(), $paths, $repository_clause, $limit_clause); $ids = ipull($data, 'id'); if (empty($ids)) { return array(); } $order = array(); foreach ($ids as $id) { if (empty($order[$id])) { $order[$id] = true; } } $packages = $package->loadAllWhere('id in (%Ld)', array_keys($order)); $packages = array_select_keys($packages, array_keys($order)); return $packages; }
protected function loadPage() { $table = new PhabricatorOwnersPackage(); $conn_r = $table->establishConnection('r'); $data = queryfx_all($conn_r, 'SELECT p.* FROM %T p %Q %Q %Q %Q', $table->getTableName(), $this->buildJoinClause($conn_r), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); return $table->loadAllFromArray($data); }
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)); }
private static function queryByPath($repo_callsign, $path) { $repository = id(new PhabricatorRepository())->loadOneWhere('callsign = %s', $repo_callsign); if (empty($repository)) { throw id(new ConduitException('ERR_REP_NOT_FOUND'))->setErrorDescription('Repository callsign ' . $repo_callsign . ' not recognized'); } return PhabricatorOwnersPackage::loadOwningPackages($repository, $path); }
public function loadAffectedPackages() { if ($this->affectedPackages === null) { $packages = PhabricatorOwnersPackage::loadAffectedPackages($this->repository, $this->loadAffectedPaths()); $this->affectedPackages = $packages; } return $this->affectedPackages; }
function testFindLongestPathsPerPackage() { $rows = array(array('id' => 1, 'excluded' => 0, 'path' => 'src/'), array('id' => 1, 'excluded' => 1, 'path' => 'src/releeph/'), array('id' => 2, 'excluded' => 0, 'path' => 'src/releeph/')); $paths = array('src/' => array('src/a.php' => true, 'src/releeph/b.php' => true), 'src/releeph/' => array('src/releeph/b.php' => true)); $this->assertEqual(array(1 => strlen('src/'), 2 => strlen('src/releeph/')), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); $paths = array('src/' => array('src/releeph/b.php' => true), 'src/releeph/' => array('src/releeph/b.php' => true)); $this->assertEqual(array(2 => strlen('src/releeph/')), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); }
private static function updateAffectedPackages($repository, array $move_map) { $paths = array_keys($move_map); if ($paths) { $packages = PhabricatorOwnersPackage::loadAffectedPackages($repository, $paths); foreach ($packages as $package) { self::updatePackagePaths($package, $move_map); } } }
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)); }
public function getTitle() { $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); $map = ipull($map, 'name'); $old = $this->getOldValue(); $new = $this->getNewValue(); $old = idx($map, $old, $old); $new = idx($map, $new, $new); return pht('%s adjusted autoreview from %s to %s.', $this->renderAuthor(), $this->renderValue($old), $this->renderValue($new)); }
public function testObjectListQuery() { $user = $this->generateNewTestUser(); $name = $user->getUsername(); $phid = $user->getPHID(); $result = $this->parseObjectList("@{$name}"); $this->assertEqual(array($phid), $result); $result = $this->parseObjectList("{$name}"); $this->assertEqual(array($phid), $result); $result = $this->parseObjectList("{$name}, {$name}"); $this->assertEqual(array($phid), $result); $result = $this->parseObjectList("@{$name}, {$name}"); $this->assertEqual(array($phid), $result); $result = $this->parseObjectList(''); $this->assertEqual(array(), $result); $result = $this->parseObjectList("{$name}!", array(), false, array('!')); $this->assertEqual(array(array('phid' => $phid, 'suffixes' => array('!' => '!'))), $result); $package = PhabricatorOwnersPackage::initializeNewPackage($user)->setName(pht('Query Test Package'))->save(); $package_phid = $package->getPHID(); $package_mono = $package->getMonogram(); $result = $this->parseObjectList("{$package_mono} Any Ignored Text"); $this->assertEqual(array($package_phid), $result); $result = $this->parseObjectList("{$package_mono} Any Text, {$name}"); $this->assertEqual(array($package_phid, $phid), $result); $result = $this->parseObjectList("{$package_mono} Any Text!, {$name}", array(), false, array('!')); $this->assertEqual(array(array('phid' => $package_phid, 'suffixes' => array('!' => '!')), array('phid' => $phid, 'suffixes' => array())), $result); // Expect failure when loading a user if objects must be of type "DUCK". $caught = null; try { $result = $this->parseObjectList("{$name}", array('DUCK')); } catch (Exception $ex) { $caught = $ex; } $this->assertTrue($caught instanceof Exception); // Expect failure when loading an invalid object. $caught = null; try { $result = $this->parseObjectList('invalid'); } catch (Exception $ex) { $caught = $ex; } $this->assertTrue($caught instanceof Exception); // Expect failure when loading ANY invalid object, by default. $caught = null; try { $result = $this->parseObjectList("{$name}, invalid"); } catch (Exception $ex) { $caught = $ex; } $this->assertTrue($caught instanceof Exception); // With partial results, this should load the valid user. $result = $this->parseObjectList("{$name}, invalid", array(), true); $this->assertEqual(array($phid), $result); }
private static function queryByPath(PhabricatorUser $viewer, $repo_callsign, $path) { $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withCallsigns(array($repo_callsign))->executeOne(); if (!$repository) { throw id(new ConduitException('ERR_REP_NOT_FOUND'))->setErrorDescription(pht('Repository callsign %s not recognized', $repo_callsign)); } if ($path == null) { return PhabricatorOwnersPackage::loadPackagesForRepository($repository); } else { return PhabricatorOwnersPackage::loadOwningPackages($repository, $path); } }
private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package, $author_phid, $revision) { $owner_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(array($package->getID())); $owner_phids = array_fuse($owner_phids); $reasons = array(); if (!$author_phid) { $reasons[] = pht('Commit Author Not Recognized'); } else { if (isset($owner_phids[$author_phid])) { return $reasons; } } if (!$revision) { $reasons[] = pht('No Revision Specified'); return $reasons; } $accepted_statuses = array(DifferentialReviewerStatus::STATUS_ACCEPTED, DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER); $accepted_statuses = array_fuse($accepted_statuses); $found_accept = false; foreach ($revision->getReviewerStatus() as $reviewer) { $reviewer_phid = $reviewer->getReviewerPHID(); // If this reviewer isn't a package owner, just ignore them. if (empty($owner_phids[$reviewer_phid])) { continue; } // If this reviewer accepted the revision and owns the package, we're // all clear and do not need to trigger an audit. if (isset($accepted_statuses[$reviewer->getStatus()])) { $found_accept = true; break; } } if (!$found_accept) { $reasons[] = pht('Owners Not Involved'); } return $reasons; }
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; }
private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package) { $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID()); $reasons = array(); if ($data->getCommitDetail('vsDiff')) { $reasons[] = 'Changed After Revision Was Accepted'; } $commit_author_phid = $data->getCommitDetail('authorPHID'); if (!$commit_author_phid) { $reasons[] = 'Commit Author Not Recognized'; } $revision_id = $data->getCommitDetail('differential.revisionID'); $revision_author_phid = null; $commit_reviewedby_phid = null; if ($revision_id) { // TODO: (T603) This is probably safe to use an omnipotent user on, // but check things more closely. $revision = id(new DifferentialRevision())->load($revision_id); if ($revision) { $revision_author_phid = $revision->getAuthorPHID(); $commit_reviewedby_phid = $data->getCommitDetail('reviewerPHID'); if ($revision_author_phid !== $commit_author_phid) { $reasons[] = 'Author Not Matching with Revision'; } } else { $reasons[] = 'Revision Not Found'; } } else { $reasons[] = 'No Revision Specified'; } $owners_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(array($package->getID())); if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $commit_reviewedby_phid && in_array($commit_reviewedby_phid, $owners_phids))) { $reasons[] = 'Owners Not Involved'; } return $reasons; }
private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package) { $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID()); $reasons = array(); $commit_author_phid = $data->getCommitDetail('authorPHID'); if (!$commit_author_phid) { $reasons[] = "Commit Author Not Recognized"; } $revision_id = $data->getCommitDetail('differential.revisionID'); $revision_author_phid = null; if ($revision_id) { $revision = id(new DifferentialRevision())->load($revision_id); if ($revision) { $revision->loadRelationships(); $revision_author_phid = $revision->getAuthorPHID(); $revision_reviewedby_phid = $revision->loadReviewedBy(); $commit_reviewedby_phid = $data->getCommitDetail('reviewerPHID'); if ($revision_author_phid !== $commit_author_phid) { $reasons[] = "Author Not Matching with Revision"; } if ($revision_reviewedby_phid !== $commit_reviewedby_phid) { $reasons[] = "ReviewedBy Not Matching with Revision"; } } else { $reasons[] = "Revision Not Found"; } } else { $reasons[] = "No Revision Specified"; } $owners = id(new PhabricatorOwnersOwner())->loadAllWhere('packageID = %d', $package->getID()); $owners_phids = mpull($owners, 'getUserPHID'); if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $revision_author_phid && in_array($revision_author_phid, $owners_phids))) { $reasons[] = "Owners Not Involved"; } return $reasons; }
protected function execute(ConduitAPIRequest $request) { $repository = id(new PhabricatorRepository())->loadOneWhere('callsign = %s', $request->getValue('repositoryCallsign')); if (empty($repository)) { throw new ConduitException('ERR_REP_NOT_FOUND'); } $packages = PhabricatorOwnersPackage::loadOwningPackages($repository, $request->getValue('path')); if (empty($packages)) { throw new ConduitException('ERR_PATH_NOT_FOUND'); } $result = array(); foreach ($packages as $package) { $p_owners = id(new PhabricatorOwnersOwner())->loadAllForPackages(array($package)); $result[] = array('phid' => $package->getPHID(), 'name' => $package->getName(), 'primaryOwner' => $package->getPrimaryOwnerPHID(), 'owners' => array_values(mpull($p_owners, 'getUserPHID'))); } return $result; }
public function testFindLongestPathsPerPackage() { $rows = array(array('id' => 1, 'excluded' => 0, 'dominion' => PhabricatorOwnersPackage::DOMINION_STRONG, 'path' => 'src/'), array('id' => 1, 'excluded' => 1, 'dominion' => PhabricatorOwnersPackage::DOMINION_STRONG, 'path' => 'src/releeph/'), array('id' => 2, 'excluded' => 0, 'dominion' => PhabricatorOwnersPackage::DOMINION_STRONG, 'path' => 'src/releeph/')); $paths = array('src/' => array('src/a.php' => true, 'src/releeph/b.php' => true), 'src/releeph/' => array('src/releeph/b.php' => true)); $this->assertEqual(array(1 => strlen('src/'), 2 => strlen('src/releeph/')), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); $paths = array('src/' => array('src/releeph/b.php' => true), 'src/releeph/' => array('src/releeph/b.php' => true)); $this->assertEqual(array(2 => strlen('src/releeph/')), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); // Test packages with weak dominion. Here, only package #2 should own the // path. Package #1's claim is ceded to Package #2 because it uses weak // rules. Package #2 gets the claim even though it also has weak rules // because there is no more-specific package. $rows = array(array('id' => 1, 'excluded' => 0, 'dominion' => PhabricatorOwnersPackage::DOMINION_WEAK, 'path' => 'src/'), array('id' => 2, 'excluded' => 0, 'dominion' => PhabricatorOwnersPackage::DOMINION_WEAK, 'path' => 'src/applications/')); $pvalue = array('src/applications/main/main.c' => true); $paths = array('src/' => $pvalue, 'src/applications/' => $pvalue); $this->assertEqual(array(2 => strlen('src/applications/')), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); // Now, add a more specific path to Package #1. This tests nested ownership // in packages with weak dominion rules. This time, Package #1 should end // up back on top, with Package #2 cedeing control to its more specific // path. $rows[] = array('id' => 1, 'excluded' => 0, 'dominion' => PhabricatorOwnersPackage::DOMINION_WEAK, 'path' => 'src/applications/main/'); $paths['src/applications/main/'] = $pvalue; $this->assertEqual(array(1 => strlen('src/applications/main/')), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); }
/** * Get the number of directory matches between this path specification and * some real path. */ public function getPathMatchStrength($path) { $this_path = $this->getPath(); if ($this_path === '/') { // The root path "/" just matches everything with strength 1. return 1; } $self_fragments = PhabricatorOwnersPackage::splitPath($this_path); $path_fragments = PhabricatorOwnersPackage::splitPath($path); $self_count = count($self_fragments); $path_count = count($path_fragments); if ($self_count > $path_count) { // If this path is longer (and therefor more specific) than the target // path, we don't match it at all. return 0; } for ($ii = 0; $ii < $self_count; $ii++) { if ($self_fragments[$ii] != $path_fragments[$ii]) { return 0; } } return $self_count; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $package = id(new PhabricatorOwnersPackage())->load($this->id); if (!$package) { return new Aphront404Response(); } } else { $package = new PhabricatorOwnersPackage(); $package->setPrimaryOwnerPHID($user->getPHID()); } $e_name = true; $e_primary = true; $e_owners = true; $errors = array(); if ($request->isFormPost()) { $package->setName($request->getStr('name')); $package->setDescription($request->getStr('description')); $primary = $request->getArr('primary'); $primary = reset($primary); $package->setPrimaryOwnerPHID($primary); $owners = $request->getArr('owners'); if ($primary) { array_unshift($owners, $primary); } $owners = array_unique($owners); $paths = $request->getArr('path'); $repos = $request->getArr('repo'); $path_refs = array(); for ($ii = 0; $ii < count($paths); $ii++) { if (empty($paths[$ii]) || empty($repos[$ii])) { continue; } $path_refs[] = array('repositoryPHID' => $repos[$ii], 'path' => $paths[$ii]); } if (!strlen($package->getName())) { $e_name = 'Required'; $errors[] = 'Package name is required.'; } else { $e_name = null; } if (!$package->getPrimaryOwnerPHID()) { $e_primary = 'Required'; $errors[] = 'Package must have a primary owner.'; } else { $e_primary = null; } if (!$owners) { $e_owners = 'Required'; $errors[] = 'Package must have at least one owner.'; } else { $e_owners = null; } if (!$path_refs) { $errors[] = 'Package must include at least one path.'; } if (!$errors) { $package->attachUnsavedOwners($owners); $package->attachUnsavedPaths($path_refs); try { $package->save(); return id(new AphrontRedirectResponse())->setURI('/owners/package/' . $package->getID() . '/'); } catch (AphrontQueryDuplicateKeyException $ex) { $e_name = 'Duplicate'; $errors[] = 'Package name must be unique.'; } } } else { $owners = $package->loadOwners(); $owners = mpull($owners, 'getUserPHID'); $paths = $package->loadPaths(); $path_refs = array(); foreach ($paths as $path) { $path_refs[] = array('repositoryPHID' => $path->getRepositoryPHID(), 'path' => $path->getPath()); } } $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setTitle('Package Errors'); $error_view->setErrors($errors); } $handles = id(new PhabricatorObjectHandleData($owners))->loadHandles(); $primary = $package->getPrimaryOwnerPHID(); if ($primary && isset($handles[$primary])) { $token_primary_owner = array($primary => $handles[$primary]->getFullName()); } else { $token_primary_owner = array(); } $token_all_owners = array_select_keys($handles, $owners); $token_all_owners = mpull($token_all_owners, 'getFullName'); $title = $package->getID() ? 'Edit Package' : 'New Package'; $repos = id(new PhabricatorRepository())->loadAll(); $default_paths = array(); foreach ($repos as $repo) { $default_path = $repo->getDetail('default-owners-path'); if ($default_path) { $default_paths[$repo->getPHID()] = $default_path; } } $repos = mpull($repos, 'getCallsign', 'getPHID'); $template = new AphrontTypeaheadTemplateView(); $template = $template->render(); Javelin::initBehavior('owners-path-editor', array('root' => 'path-editor', 'table' => 'paths', 'add_button' => 'addpath', 'repositories' => $repos, 'input_template' => $template, 'pathRefs' => $path_refs, 'completeURI' => '/diffusion/services/path/complete/', 'validateURI' => '/diffusion/services/path/validate/', 'repositoryDefaultPaths' => $default_paths)); require_celerity_resource('owners-path-editor-css'); $cancel_uri = $package->getID() ? '/owners/package/' . $package->getID() . '/' : '/owners/'; $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($package->getName())->setError($e_name))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setLabel('Primary Owner')->setName('primary')->setLimit(1)->setValue($token_primary_owner)->setError($e_primary))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setLabel('Owners')->setName('owners')->setValue($token_all_owners)->setError($e_owners))->appendChild('<h1>Paths</h1>' . '<div class="aphront-form-inset" id="path-editor">' . '<div style="float: right;">' . javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'addpath', 'mustcapture' => true), 'Add New Path') . '</div>' . '<p>Specify the files and directories which comprise this ' . 'package.</p>' . '<div style="clear: both;"></div>' . javelin_render_tag('table', array('class' => 'owners-path-editor-table', 'sigil' => 'paths'), '') . '</div>')->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Description')->setName('description')->setValue($package->getDescription()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue('Save Package')); $panel = new AphrontPanelView(); $panel->setHeader($title); $panel->setWidth(AphrontPanelView::WIDTH_WIDE); $panel->appendChild($error_view); $panel->appendChild($form); return $this->buildStandardPageResponse($panel, array('title' => $title)); }
public static function loadPackagesForRepository($repository) { $package = new PhabricatorOwnersPackage(); $ids = ipull(queryfx_all($package->establishConnection('r'), 'SELECT DISTINCT packageID FROM %T WHERE repositoryPHID = %s', id(new PhabricatorOwnersPath())->getTableName(), $repository->getPHID()), 'packageID'); return $package->loadAllWhere('id in (%Ld)', $ids); }
protected function newEditableObject() { return PhabricatorOwnersPackage::initializeNewPackage($this->getViewer()); }
private function getFragmentsForPaths(array $paths) { $fragments = array(); foreach ($paths as $path) { foreach (PhabricatorOwnersPackage::splitPath($path) as $fragment) { $fragments[$fragment] = $fragment; } } return $fragments; }
private function buildPackageActionView(PhabricatorOwnersPackage $package) { $viewer = $this->getViewer(); // TODO: Implement this capability. $can_edit = true; $id = $package->getID(); $edit_uri = $this->getApplicationURI("/edit/{$id}/"); $paths_uri = $this->getApplicationURI("/paths/{$id}/"); $view = id(new PhabricatorActionListView())->setUser($viewer)->setObject($package)->addAction(id(new PhabricatorActionView())->setName(pht('Edit Package'))->setIcon('fa-pencil')->setDisabled(!$can_edit)->setWorkflow(!$can_edit)->setHref($edit_uri))->addAction(id(new PhabricatorActionView())->setName(pht('Edit Paths'))->setIcon('fa-folder-open')->setDisabled(!$can_edit)->setWorkflow(!$can_edit)->setHref($paths_uri)); return $view; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); $id = $request->getURIData('id'); if ($id) { $package = id(new PhabricatorOwnersPackageQuery())->setViewer($viewer)->withIDs(array($id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW))->needOwners(true)->executeOne(); if (!$package) { return new Aphront404Response(); } $is_new = false; } else { $package = PhabricatorOwnersPackage::initializeNewPackage($viewer); $is_new = true; } $e_name = true; $v_name = $package->getName(); $v_owners = mpull($package->getOwners(), 'getUserPHID'); $v_auditing = $package->getAuditingEnabled(); $v_description = $package->getDescription(); $v_status = $package->getStatus(); $errors = array(); if ($request->isFormPost()) { $xactions = array(); $v_name = $request->getStr('name'); $v_owners = $request->getArr('owners'); $v_auditing = $request->getStr('auditing') == 'enabled'; $v_description = $request->getStr('description'); $v_status = $request->getStr('status'); $type_name = PhabricatorOwnersPackageTransaction::TYPE_NAME; $type_owners = PhabricatorOwnersPackageTransaction::TYPE_OWNERS; $type_auditing = PhabricatorOwnersPackageTransaction::TYPE_AUDITING; $type_description = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION; $type_status = PhabricatorOwnersPackageTransaction::TYPE_STATUS; $xactions[] = id(new PhabricatorOwnersPackageTransaction())->setTransactionType($type_name)->setNewValue($v_name); $xactions[] = id(new PhabricatorOwnersPackageTransaction())->setTransactionType($type_owners)->setNewValue($v_owners); $xactions[] = id(new PhabricatorOwnersPackageTransaction())->setTransactionType($type_auditing)->setNewValue($v_auditing); $xactions[] = id(new PhabricatorOwnersPackageTransaction())->setTransactionType($type_description)->setNewValue($v_description); if (!$is_new) { $xactions[] = id(new PhabricatorOwnersPackageTransaction())->setTransactionType($type_status)->setNewValue($v_status); } $editor = id(new PhabricatorOwnersPackageTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true); try { $editor->applyTransactions($package, $xactions); $id = $package->getID(); if ($is_new) { $next_uri = '/owners/paths/' . $id . '/'; } else { $next_uri = '/owners/package/' . $id . '/'; } return id(new AphrontRedirectResponse())->setURI($next_uri); } catch (AphrontDuplicateKeyQueryException $ex) { $e_name = pht('Duplicate'); $errors[] = pht('Package name must be unique.'); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); } } if ($is_new) { $cancel_uri = '/owners/'; $title = pht('New Package'); $button_text = pht('Continue'); } else { $cancel_uri = '/owners/package/' . $package->getID() . '/'; $title = pht('Edit Package'); $button_text = pht('Save Package'); } $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Name'))->setName('name')->setValue($v_name)->setError($e_name))->appendControl(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectOrUserDatasource())->setLabel(pht('Owners'))->setName('owners')->setValue($v_owners)); if (!$is_new) { $form->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('status')->setValue($v_status)->setOptions($package->getStatusNameMap())); } $form->appendChild(id(new AphrontFormSelectControl())->setName('auditing')->setLabel(pht('Auditing'))->setCaption(pht('With auditing enabled, all future commits that touch ' . 'this package will be reviewed to make sure an owner ' . 'of the package is involved and the commit message has ' . 'a valid revision, reviewed by, and author.'))->setOptions(array('disabled' => pht('Disabled'), 'enabled' => pht('Enabled')))->setValue($v_auditing ? 'enabled' : 'disabled'))->appendChild(id(new PhabricatorRemarkupControl())->setUser($viewer)->setLabel(pht('Description'))->setName('description')->setValue($v_description))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($button_text)); $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->setForm($form); $crumbs = $this->buildApplicationCrumbs(); if ($package->getID()) { $crumbs->addTextCrumb($package->getName(), $this->getApplicationURI('package/' . $package->getID() . '/')); $crumbs->addTextCrumb(pht('Edit')); } else { $crumbs->addTextCrumb(pht('New Package')); } return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => $title)); }
public function loadHandles() { $types = phid_group_by_type($this->phids); $handles = array(); $external_loaders = PhabricatorEnv::getEnvConfig('phid.external-loaders'); foreach ($types as $type => $phids) { switch ($type) { case PhabricatorPHIDConstants::PHID_TYPE_MAGIC: // Black magic! foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); switch ($phid) { case ManiphestTaskOwner::OWNER_UP_FOR_GRABS: $handle->setName('Up For Grabs'); $handle->setFullName('upforgrabs (Up For Grabs)'); $handle->setComplete(true); break; case ManiphestTaskOwner::PROJECT_NO_PROJECT: $handle->setName('No Project'); $handle->setFullName('noproject (No Project)'); $handle->setComplete(true); break; default: $handle->setName('Foul Magicks'); break; } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_USER: $object = new PhabricatorUser(); $users = $object->loadAllWhere('phid IN (%Ls)', $phids); $users = mpull($users, null, 'getPHID'); $image_phids = mpull($users, 'getProfileImagePHID'); $image_phids = array_unique(array_filter($image_phids)); $images = array(); if ($image_phids) { $images = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $image_phids); $images = mpull($images, 'getBestURI', 'getPHID'); } $statuses = id(new PhabricatorUserStatus())->loadCurrentStatuses($phids); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($users[$phid])) { $handle->setName('Unknown User'); } else { $user = $users[$phid]; $handle->setName($user->getUsername()); $handle->setURI('/p/' . $user->getUsername() . '/'); $handle->setFullName($user->getUsername() . ' (' . $user->getRealName() . ')'); $handle->setAlternateID($user->getID()); $handle->setComplete(true); if (isset($statuses[$phid])) { $handle->setStatus($statuses[$phid]->getTextStatus()); } $handle->setDisabled($user->getIsDisabled()); $img_uri = idx($images, $user->getProfileImagePHID()); if ($img_uri) { $handle->setImageURI($img_uri); } else { $handle->setImageURI(PhabricatorUser::getDefaultProfileImageURI()); } } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_MLST: $object = new PhabricatorMetaMTAMailingList(); $lists = $object->loadAllWhere('phid IN (%Ls)', $phids); $lists = mpull($lists, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($lists[$phid])) { $handle->setName('Unknown Mailing List'); } else { $list = $lists[$phid]; $handle->setName($list->getName()); $handle->setURI($list->getURI()); $handle->setFullName($list->getName()); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_DREV: $object = new DifferentialRevision(); $revs = $object->loadAllWhere('phid in (%Ls)', $phids); $revs = mpull($revs, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($revs[$phid])) { $handle->setName('Unknown Revision'); } else { $rev = $revs[$phid]; $handle->setName($rev->getTitle()); $handle->setURI('/D' . $rev->getID()); $handle->setFullName('D' . $rev->getID() . ': ' . $rev->getTitle()); $handle->setComplete(true); $status = $rev->getStatus(); if ($status == ArcanistDifferentialRevisionStatus::CLOSED || $status == ArcanistDifferentialRevisionStatus::ABANDONED) { $closed = PhabricatorObjectHandleStatus::STATUS_CLOSED; $handle->setStatus($closed); } } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_CMIT: $object = new PhabricatorRepositoryCommit(); $commits = $object->loadAllWhere('phid in (%Ls)', $phids); $commits = mpull($commits, null, 'getPHID'); $repository_ids = array(); $callsigns = array(); if ($commits) { $repository_ids = mpull($commits, 'getRepositoryID'); $repositories = id(new PhabricatorRepository())->loadAllWhere('id in (%Ld)', array_unique($repository_ids)); $callsigns = mpull($repositories, 'getCallsign'); } foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($commits[$phid]) || !isset($callsigns[$repository_ids[$phid]])) { $handle->setName('Unknown Commit'); } else { $commit = $commits[$phid]; $callsign = $callsigns[$repository_ids[$phid]]; $repository = $repositories[$repository_ids[$phid]]; $commit_identifier = $commit->getCommitIdentifier(); // In case where the repository for the commit was deleted, // we don't have have info about the repository anymore. if ($repository) { $name = $repository->formatCommitName($commit_identifier); $handle->setName($name); } else { $handle->setName('Commit ' . 'r' . $callsign . $commit_identifier); } $handle->setURI('/r' . $callsign . $commit_identifier); $handle->setFullName('r' . $callsign . $commit_identifier); $handle->setTimestamp($commit->getEpoch()); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_TASK: $object = new ManiphestTask(); $tasks = $object->loadAllWhere('phid in (%Ls)', $phids); $tasks = mpull($tasks, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($tasks[$phid])) { $handle->setName('Unknown Revision'); } else { $task = $tasks[$phid]; $handle->setName($task->getTitle()); $handle->setURI('/T' . $task->getID()); $handle->setFullName('T' . $task->getID() . ': ' . $task->getTitle()); $handle->setComplete(true); $handle->setAlternateID($task->getID()); if ($task->getStatus() != ManiphestTaskStatus::STATUS_OPEN) { $closed = PhabricatorObjectHandleStatus::STATUS_CLOSED; $handle->setStatus($closed); } } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_FILE: $object = new PhabricatorFile(); $files = $object->loadAllWhere('phid IN (%Ls)', $phids); $files = mpull($files, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($files[$phid])) { $handle->setName('Unknown File'); } else { $file = $files[$phid]; $handle->setName($file->getName()); $handle->setURI($file->getBestURI()); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_PROJ: $object = new PhabricatorProject(); $projects = $object->loadAllWhere('phid IN (%Ls)', $phids); $projects = mpull($projects, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($projects[$phid])) { $handle->setName('Unknown Project'); } else { $project = $projects[$phid]; $handle->setName($project->getName()); $handle->setURI('/project/view/' . $project->getID() . '/'); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_REPO: $object = new PhabricatorRepository(); $repositories = $object->loadAllWhere('phid in (%Ls)', $phids); $repositories = mpull($repositories, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($repositories[$phid])) { $handle->setName('Unknown Repository'); } else { $repository = $repositories[$phid]; $handle->setName($repository->getCallsign()); $handle->setURI('/diffusion/' . $repository->getCallsign() . '/'); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_OPKG: $object = new PhabricatorOwnersPackage(); $packages = $object->loadAllWhere('phid in (%Ls)', $phids); $packages = mpull($packages, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($packages[$phid])) { $handle->setName('Unknown Package'); } else { $package = $packages[$phid]; $handle->setName($package->getName()); $handle->setURI('/owners/package/' . $package->getID() . '/'); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_APRJ: $project_dao = new PhabricatorRepositoryArcanistProject(); $projects = $project_dao->loadAllWhere('phid IN (%Ls)', $phids); $projects = mpull($projects, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($projects[$phid])) { $handle->setName('Unknown Arcanist Project'); } else { $project = $projects[$phid]; $handle->setName($project->getName()); $handle->setComplete(true); } $handles[$phid] = $handle; } break; case PhabricatorPHIDConstants::PHID_TYPE_WIKI: $document_dao = new PhrictionDocument(); $content_dao = new PhrictionContent(); $conn = $document_dao->establishConnection('r'); $documents = queryfx_all($conn, 'SELECT * FROM %T document JOIN %T content ON document.contentID = content.id WHERE document.phid IN (%Ls)', $document_dao->getTableName(), $content_dao->getTableName(), $phids); $documents = ipull($documents, null, 'phid'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); if (empty($documents[$phid])) { $handle->setName('Unknown Document'); } else { $info = $documents[$phid]; $handle->setName($info['title']); $handle->setURI(PhrictionDocument::getSlugURI($info['slug'])); $handle->setComplete(true); } $handles[$phid] = $handle; } break; default: $loader = null; if (isset($external_loaders[$type])) { $loader = $external_loaders[$type]; } else { if (isset($external_loaders['*'])) { $loader = $external_loaders['*']; } } if ($loader) { $object = newv($loader, array()); $handles += $object->loadHandles($phids); break; } foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setType($type); $handle->setPHID($phid); $handle->setName('Unknown Object'); $handle->setFullName('An Unknown Object'); $handles[$phid] = $handle; } break; } } return $handles; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $package = id(new PhabricatorOwnersPackage())->load($this->id); if (!$package) { return new Aphront404Response(); } } else { $package = new PhabricatorOwnersPackage(); $package->setPrimaryOwnerPHID($user->getPHID()); } $e_name = true; $e_primary = true; $errors = array(); if ($request->isFormPost()) { $package->setName($request->getStr('name')); $package->setDescription($request->getStr('description')); $old_auditing_enabled = $package->getAuditingEnabled(); $package->setAuditingEnabled($request->getStr('auditing') === 'enabled' ? 1 : 0); $primary = $request->getArr('primary'); $primary = reset($primary); $old_primary = $package->getPrimaryOwnerPHID(); $package->setPrimaryOwnerPHID($primary); $owners = $request->getArr('owners'); if ($primary) { array_unshift($owners, $primary); } $owners = array_unique($owners); $paths = $request->getArr('path'); $repos = $request->getArr('repo'); $excludes = $request->getArr('exclude'); $path_refs = array(); for ($ii = 0; $ii < count($paths); $ii++) { if (empty($paths[$ii]) || empty($repos[$ii])) { continue; } $path_refs[] = array('repositoryPHID' => $repos[$ii], 'path' => $paths[$ii], 'excluded' => $excludes[$ii]); } if (!strlen($package->getName())) { $e_name = pht('Required'); $errors[] = pht('Package name is required.'); } else { $e_name = null; } if (!$package->getPrimaryOwnerPHID()) { $e_primary = pht('Required'); $errors[] = pht('Package must have a primary owner.'); } else { $e_primary = null; } if (!$path_refs) { $errors[] = pht('Package must include at least one path.'); } if (!$errors) { $package->attachUnsavedOwners($owners); $package->attachUnsavedPaths($path_refs); $package->attachOldAuditingEnabled($old_auditing_enabled); $package->attachOldPrimaryOwnerPHID($old_primary); $package->attachActorPHID($user->getPHID()); try { $package->save(); return id(new AphrontRedirectResponse())->setURI('/owners/package/' . $package->getID() . '/'); } catch (AphrontDuplicateKeyQueryException $ex) { $e_name = pht('Duplicate'); $errors[] = pht('Package name must be unique.'); } } } else { $owners = $package->loadOwners(); $owners = mpull($owners, 'getUserPHID'); $paths = $package->loadPaths(); $path_refs = array(); foreach ($paths as $path) { $path_refs[] = array('repositoryPHID' => $path->getRepositoryPHID(), 'path' => $path->getPath(), 'excluded' => $path->getExcluded()); } } $handles = $this->loadViewerHandles($owners); $primary = $package->getPrimaryOwnerPHID(); if ($primary && isset($handles[$primary])) { $handle_primary_owner = array($handles[$primary]); } else { $handle_primary_owner = array(); } $handles_all_owners = array_select_keys($handles, $owners); if ($package->getID()) { $title = pht('Edit Package'); $side_nav_filter = 'edit/' . $this->id; } else { $title = pht('New Package'); $side_nav_filter = 'new'; } $this->setSideNavFilter($side_nav_filter); $repos = id(new PhabricatorRepositoryQuery())->setViewer($user)->execute(); $default_paths = array(); foreach ($repos as $repo) { $default_path = $repo->getDetail('default-owners-path'); if ($default_path) { $default_paths[$repo->getPHID()] = $default_path; } } $repos = mpull($repos, 'getCallsign', 'getPHID'); $template = new AphrontTypeaheadTemplateView(); $template = $template->render(); Javelin::initBehavior('owners-path-editor', array('root' => 'path-editor', 'table' => 'paths', 'add_button' => 'addpath', 'repositories' => $repos, 'input_template' => $template, 'pathRefs' => $path_refs, 'completeURI' => '/diffusion/services/path/complete/', 'validateURI' => '/diffusion/services/path/validate/', 'repositoryDefaultPaths' => $default_paths)); require_celerity_resource('owners-path-editor-css'); $cancel_uri = $package->getID() ? '/owners/package/' . $package->getID() . '/' : '/owners/'; $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Name'))->setName('name')->setValue($package->getName())->setError($e_name))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectOrUserDatasource())->setLabel(pht('Primary Owner'))->setName('primary')->setLimit(1)->setValue($handle_primary_owner)->setError($e_primary))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectOrUserDatasource())->setLabel(pht('Owners'))->setName('owners')->setValue($handles_all_owners))->appendChild(id(new AphrontFormSelectControl())->setName('auditing')->setLabel(pht('Auditing'))->setCaption(pht('With auditing enabled, all future commits that touch ' . 'this package will be reviewed to make sure an owner ' . 'of the package is involved and the commit message has ' . 'a valid revision, reviewed by, and author.'))->setOptions(array('disabled' => pht('Disabled'), 'enabled' => pht('Enabled')))->setValue($package->getAuditingEnabled() ? 'enabled' : 'disabled'))->appendChild(id(new AphrontFormInsetView())->setTitle(pht('Paths'))->addDivAttributes(array('id' => 'path-editor'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'addpath', 'mustcapture' => true), pht('Add New Path')))->setDescription(pht('Specify the files and directories which comprise ' . 'this package.'))->setContent(javelin_tag('table', array('class' => 'owners-path-editor-table', 'sigil' => 'paths'), '')))->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Description'))->setName('description')->setValue($package->getDescription()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue(pht('Save Package'))); $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->setForm($form); $nav = $this->buildSideNavView(); $nav->appendChild($form_box); return $this->buildApplicationPage(array($nav), array('title' => $title)); }
protected function didApplyHeraldRules(PhabricatorLiskDAO $object, HeraldAdapter $adapter, HeraldTranscript $transcript) { $repository = $object->getRepository(); if (!$repository) { return array(); } if (!$this->affectedPaths) { return array(); } $packages = PhabricatorOwnersPackage::loadAffectedPackages($repository, $this->affectedPaths); if (!$packages) { return array(); } // Remove packages that the revision author is an owner of. If you own // code, you don't need another owner to review it. $authority = id(new PhabricatorOwnersPackageQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs(mpull($packages, 'getPHID'))->withAuthorityPHIDs(array($object->getAuthorPHID()))->execute(); $authority = mpull($authority, null, 'getPHID'); foreach ($packages as $key => $package) { $package_phid = $package->getPHID(); if (isset($authority[$package_phid])) { unset($packages[$key]); continue; } } if (!$packages) { return array(); } $auto_subscribe = array(); $auto_review = array(); $auto_block = array(); foreach ($packages as $package) { switch ($package->getAutoReview()) { case PhabricatorOwnersPackage::AUTOREVIEW_SUBSCRIBE: $auto_subscribe[] = $package; break; case PhabricatorOwnersPackage::AUTOREVIEW_REVIEW: $auto_review[] = $package; break; case PhabricatorOwnersPackage::AUTOREVIEW_BLOCK: $auto_block[] = $package; break; case PhabricatorOwnersPackage::AUTOREVIEW_NONE: default: break; } } $owners_phid = id(new PhabricatorOwnersApplication())->getPHID(); $xactions = array(); if ($auto_subscribe) { $xactions[] = $object->getApplicationTransactionTemplate()->setAuthorPHID($owners_phid)->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)->setNewValue(array('+' => mpull($auto_subscribe, 'getPHID'))); } $specs = array(array($auto_review, false), array($auto_block, true)); foreach ($specs as $spec) { list($reviewers, $blocking) = $spec; if (!$reviewers) { continue; } $phids = mpull($reviewers, 'getPHID'); $xaction = $this->newAutoReviewTransaction($object, $phids, $blocking); if ($xaction) { $xactions[] = $xaction; } } return $xactions; }
private static function loadPackagesForPaths(PhabricatorRepository $repository, array $paths, $limit = 0) { $package = new PhabricatorOwnersPackage(); $path = new PhabricatorOwnersPath(); $conn = $package->establishConnection('r'); $repository_clause = qsprintf($conn, 'AND p.repositoryPHID = %s', $repository->getPHID()); // NOTE: The list of $paths may be very large if we're coming from // the OwnersWorker and processing, e.g., an SVN commit which created a new // branch. Break it apart so that it will fit within 'max_allowed_packet', // and then merge results in PHP. $ids = array(); foreach (array_chunk($paths, 128) as $chunk) { $rows = queryfx_all($conn, 'SELECT pkg.id id, LENGTH(p.path) len FROM %T pkg JOIN %T p ON p.packageID = pkg.id WHERE p.path IN (%Ls) %Q', $package->getTableName(), $path->getTableName(), $chunk, $repository_clause); foreach ($rows as $row) { $id = (int) $row['id']; $len = (int) $row['len']; if (isset($ids[$id])) { $ids[$id] = max($len, $ids[$id]); } else { $ids[$id] = $len; } } } if (!$ids) { return array(); } arsort($ids); if ($limit) { $ids = array_slice($ids, 0, $limit, $preserve_keys = true); } $ids = array_keys($ids); $packages = $package->loadAllWhere('id in (%Ld)', $ids); $packages = array_select_keys($packages, $ids); return $packages; }