1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 10:12:41 +01:00

Add repositories to Diviner

Summary: Fixes T8352. Associate Diviner books and atoms with a repository. This relationship is not really surfaced anywhere in the UI but provides metadata that contextualises search results. Depends on D13091.

Test Plan: Ran `diviner generate --repository ARC` and then went to `/diviner/book/arcanist/`.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7703, T8352

Differential Revision: https://secure.phabricator.com/D13070
This commit is contained in:
Joshua Spence 2015-06-19 17:24:23 +10:00
parent 70a82017b3
commit 69d12f64ba
15 changed files with 262 additions and 19 deletions

View file

@ -0,0 +1,5 @@
ALTER TABLE {$NAMESPACE}_diviner.diviner_livebook
ADD COLUMN repositoryPHID VARBINARY(64) AFTER name;
ALTER TABLE {$NAMESPACE}_diviner.diviner_livesymbol
ADD COLUMN repositoryPHID VARBINARY(64) AFTER bookPHID;

View file

@ -85,6 +85,7 @@ final class DivinerAtomController extends DivinerController {
if ($atom) {
$this->buildDefined($properties, $symbol);
$this->buildExtendsAndImplements($properties, $symbol);
$this->buildRepository($properties, $symbol);
$warnings = $atom->getWarnings();
if ($warnings) {
@ -295,6 +296,15 @@ final class DivinerAtomController extends DivinerController {
}
}
private function buildRepository(
PHUIPropertyListView $view,
DivinerLiveSymbol $symbol) {
$view->addProperty(
pht('Repository'),
$this->getViewer()->renderHandle($symbol->getRepositoryPHID()));
}
private function renderAtomTag(DivinerLiveSymbol $symbol) {
return id(new PHUITagView())
->setType(PHUITagView::TYPE_OBJECT)

View file

@ -14,6 +14,7 @@ final class DivinerBookController extends DivinerController {
$book = id(new DivinerBookQuery())
->setViewer($viewer)
->withNames(array($book_name))
->needRepositories(true)
->executeOne();
if (!$book) {
@ -43,6 +44,15 @@ final class DivinerBookController extends DivinerController {
->setEpoch($book->getDateModified())
->addActionLink($action_button);
// TODO: This could probably look better.
if ($book->getRepositoryPHID()) {
$header->addTag(
id(new PHUITagView())
->setType(PHUITagView::TYPE_STATE)
->setBackgroundColor(PHUITagView::COLOR_BLUE)
->setName($book->getRepository()->getMonogram()));
}
$document = new PHUIDocumentView();
$document->setHeader($header);
$document->addClass('diviner-view');

View file

@ -75,6 +75,16 @@ final class DivinerBookEditController extends DivinerController {
->setName('projectPHIDs')
->setLabel(pht('Projects'))
->setValue($book->getProjectPHIDs()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new DiffusionRepositoryDatasource())
->setName('repositoryPHIDs')
->setLabel(pht('Repository'))
->setDisableBehavior(true)
->setLimit(1)
->setValue($book->getRepositoryPHID()
? array($book->getRepositoryPHID())
: null))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('viewPolicy')

View file

@ -4,7 +4,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
private $book;
private function loadBook() {
protected function getBook() {
if (!$this->book) {
$book_name = $this->getConfig('name');
@ -20,7 +20,24 @@ final class DivinerLivePublisher extends DivinerPublisher {
->save();
}
$book->setConfigurationData($this->getConfigurationData())->save();
$conn_w = $book->establishConnection('w');
$conn_w->openTransaction();
$book
->setRepositoryPHID($this->getRepositoryPHID())
->setConfigurationData($this->getConfigurationData())
->save();
// TODO: This is gross. Without this, the repository won't be updated for
// atoms which have already been published.
queryfx(
$conn_w,
'UPDATE %T SET repositoryPHID = %s WHERE bookPHID = %s',
id(new DivinerLiveSymbol())->getTableName(),
$this->getRepositoryPHID(),
$book->getPHID());
$conn_w->saveTransaction();
$this->book = $book;
id(new PhabricatorSearchIndexer())
@ -33,7 +50,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
private function loadSymbolForAtom(DivinerAtom $atom) {
$symbol = id(new DivinerAtomQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withBookPHIDs(array($this->loadBook()->getPHID()))
->withBookPHIDs(array($atom->getBook()))
->withTypes(array($atom->getType()))
->withNames(array($atom->getName()))
->withContexts(array($atom->getContext()))
@ -45,7 +62,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
}
return id(new DivinerLiveSymbol())
->setBookPHID($this->loadBook()->getPHID())
->setBookPHID($this->getBook()->getPHID())
->setType($atom->getType())
->setName($atom->getName())
->setContext($atom->getContext())
@ -68,7 +85,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
protected function loadAllPublishedHashes() {
$symbols = id(new DivinerAtomQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withBookPHIDs(array($this->loadBook()->getPHID()))
->withBookPHIDs(array($this->getBook()->getPHID()))
->withGhosts(false)
->execute();
@ -113,6 +130,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
$is_documentable = $this->shouldGenerateDocumentForAtom($atom);
$symbol
->setRepositoryPHID($this->getRepositoryPHID())
->setGraphHash($hash)
->setIsDocumentable((int)$is_documentable)
->setTitle($ref->getTitle())

View file

@ -9,6 +9,7 @@ abstract class DivinerPublisher extends Phobject {
private $config;
private $symbolReverseMap;
private $dropCaches;
private $repositoryPHID;
final public function setDropCaches($drop_caches) {
$this->dropCaches = $drop_caches;
@ -163,4 +164,13 @@ abstract class DivinerPublisher extends Phobject {
return true;
}
final public function getRepositoryPHID() {
return $this->repositoryPHID;
}
final public function setRepositoryPHID($repository_phid) {
$this->repositoryPHID = $repository_phid;
return $this;
}
}

View file

@ -14,10 +14,12 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
private $nodeHashes;
private $titles;
private $nameContains;
private $repositoryPHIDs;
private $needAtoms;
private $needExtends;
private $needChildren;
private $needRepositories;
public function withIDs(array $ids) {
$this->ids = $ids;
@ -109,6 +111,16 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this;
}
public function withRepositoryPHIDs(array $repository_phids) {
$this->repositoryPHIDs = $repository_phids;
return $this;
}
public function needRepositories($need_repositories) {
$this->needRepositories = $need_repositories;
return $this;
}
protected function loadPage() {
$table = new DivinerLiveSymbol();
$conn_r = $table->establishConnection('r');
@ -125,6 +137,8 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
}
protected function willFilterPage(array $atoms) {
assert_instances_of($atoms, 'DivinerLiveSymbol');
$books = array_unique(mpull($atoms, 'getBookPHID'));
$books = id(new DivinerBookQuery())
@ -257,6 +271,31 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$this->attachAllChildren($atoms, $children, $this->needExtends);
}
if ($this->needRepositories) {
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($this->getViewer())
->withPHIDs(mpull($atoms, 'getRepositoryPHID'))
->execute();
$repositories = mpull($repositories, null, 'getPHID');
foreach ($atoms as $key => $atom) {
if ($atom->getRepositoryPHID() === null) {
$atom->attachRepository(null);
continue;
}
$repository = idx($repositories, $atom->getRepositoryPHID());
if (!$repository) {
$this->didRejectResult($atom);
unset($atom[$key]);
continue;
}
$atom->attachRepository($repository);
}
}
return $atoms;
}
@ -381,6 +420,13 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$this->nameContains);
}
if ($this->repositoryPHIDs) {
$where[] = qsprintf(
$conn_r,
'repositoryPHID IN (%Ls)',
$this->repositoryPHIDs);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);

View file

@ -13,21 +13,23 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'repositoryPHIDs',
$this->readPHIDsFromRequest($request, 'repositoryPHIDs'));
$saved->setParameter('name', $request->getStr('name'));
$saved->setParameter(
'types',
$this->readListFromRequest($request, 'types'));
$saved->setParameter('name', $request->getStr('name'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new DivinerAtomQuery());
$types = $saved->getParameter('types');
if ($types) {
$query->withTypes($types);
$repository_phids = $saved->getParameter('repositoryPHIDs');
if ($repository_phids) {
$query->withRepositoryPHIDs($repository_phids);
}
$name = $saved->getParameter('name');
@ -35,6 +37,11 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
$query->withNameContains($name);
}
$types = $saved->getParameter('types');
if ($types) {
$query->withTypes($types);
}
return $query;
}
@ -42,6 +49,12 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name Contains'))
->setName('name')
->setValue($saved->getParameter('name')));
$all_types = array();
foreach (DivinerAtom::getAllTypes() as $type) {
$all_types[$type] = DivinerAtom::getAtomTypeNameString($type);
@ -59,14 +72,14 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
$name,
isset($types[$type]));
}
$form->appendChild($type_control);
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name Contains'))
->setName('name')
->setValue($saved->getParameter('name')))
->appendChild($type_control);
$form->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Repositories'))
->setName('repositoryPHIDs')
->setDatasource(new DiffusionRepositoryDatasource())
->setValue($saved->getParameter('repositoryPHIDs')));
}
protected function getURI($path) {

View file

@ -5,8 +5,10 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $names;
private $repositoryPHIDs;
private $needProjectPHIDs;
private $needRepositories;
public function withIDs(array $ids) {
$this->ids = $ids;
@ -23,11 +25,21 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this;
}
public function withRepositoryPHIDs(array $repository_phids) {
$this->repositoryPHIDs = $repository_phids;
return $this;
}
public function needProjectPHIDs($need_phids) {
$this->needProjectPHIDs = $need_phids;
return $this;
}
public function needRepositories($need_repositories) {
$this->needRepositories = $need_repositories;
return $this;
}
protected function loadPage() {
$table = new DivinerLiveBook();
$conn_r = $table->establishConnection('r');
@ -46,6 +58,31 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
protected function didFilterPage(array $books) {
assert_instances_of($books, 'DivinerLiveBook');
if ($this->needRepositories) {
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($this->getViewer())
->withPHIDs(mpull($books, 'getRepositoryPHID'))
->execute();
$repositories = mpull($repositories, null, 'getPHID');
foreach ($books as $key => $book) {
if ($book->getRepositoryPHID() === null) {
$book->attachRepository(null);
continue;
}
$repository = idx($repositories, $book->getRepositoryPHID());
if (!$repository) {
$this->didRejectResult($book);
unset($books[$key]);
continue;
}
$book->attachRepository($repository);
}
}
if ($this->needProjectPHIDs) {
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($books, 'getPHID'))
@ -91,6 +128,13 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$this->names);
}
if ($this->repositoryPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'repositoryPHID IN (%Ls)',
$this->repositoryPHIDs);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);

View file

@ -29,6 +29,12 @@ final class DivinerAtomSearchIndexer extends PhabricatorSearchDocumentIndexer {
DivinerBookPHIDType::TYPECONST,
PhabricatorTime::getNow());
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
$atom->getRepositoryPHID(),
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
PhabricatorTime::getNow());
$doc->addRelationship(
$atom->getGraphHash()
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED

View file

@ -18,6 +18,12 @@ final class DivinerBookSearchIndexer extends PhabricatorSearchDocumentIndexer {
PhabricatorSearchDocumentFieldType::FIELD_BODY,
$book->getPreface());
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
$book->getRepositoryPHID(),
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
$book->getDateCreated());
$this->indexTransactions(
$doc,
new DivinerLiveBookTransactionQuery(),

View file

@ -8,11 +8,13 @@ final class DivinerLiveBook extends DivinerDAO
PhabricatorApplicationTransactionInterface {
protected $name;
protected $repositoryPHID;
protected $viewPolicy;
protected $editPolicy;
protected $configurationData = array();
private $projectPHIDs = self::ATTACHABLE;
private $repository = self::ATTACHABLE;
protected function getConfiguration() {
return array(
@ -22,6 +24,7 @@ final class DivinerLiveBook extends DivinerDAO
),
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'text64',
'repositoryPHID' => 'phid?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
@ -68,6 +71,15 @@ final class DivinerLiveBook extends DivinerDAO
return idx($spec, 'name', $group);
}
public function attachRepository(PhabricatorRepository $repository = null) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->assertAttached($this->repository);
}
public function attachProjectPHIDs(array $project_phids) {
$this->projectPHIDs = $project_phids;
return $this;
@ -98,7 +110,7 @@ final class DivinerLiveBook extends DivinerDAO
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
return false;
}
public function describeAutomaticCapability($capability) {

View file

@ -7,6 +7,7 @@ final class DivinerLiveSymbol extends DivinerDAO
PhabricatorDestructibleInterface {
protected $bookPHID;
protected $repositoryPHID;
protected $context;
protected $type;
protected $name;
@ -22,6 +23,7 @@ final class DivinerLiveSymbol extends DivinerDAO
protected $isDocumentable = 0;
private $book = self::ATTACHABLE;
private $repository = self::ATTACHABLE;
private $atom = self::ATTACHABLE;
private $extends = self::ATTACHABLE;
private $children = self::ATTACHABLE;
@ -43,6 +45,7 @@ final class DivinerLiveSymbol extends DivinerDAO
'summary' => 'text?',
'isDocumentable' => 'bool',
'nodeHash' => 'text64?',
'repositoryPHID' => 'phid?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
@ -94,6 +97,15 @@ final class DivinerLiveSymbol extends DivinerDAO
return $this;
}
public function getRepository() {
return $this->assertAttached($this->repository);
}
public function attachRepository(PhabricatorRepository $repository = null) {
$this->repository = $repository;
return $this;
}
public function getAtom() {
return $this->assertAttached($this->atom);
}

View file

@ -25,6 +25,11 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
'help' => pht('Specify a subclass of %s.', 'DivinerPublisher'),
'default' => 'DivinerLivePublisher',
),
array(
'name' => 'repository',
'param' => 'callsign',
'help' => pht('Repository that the documentation belongs to.'),
),
));
}
@ -187,6 +192,24 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
}
$publisher = newv($publisher_class, array());
$callsign = $args->getArg('repository');
$repository = null;
if ($callsign) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withCallsigns(array($callsign))
->executeOne();
if (!$repository) {
throw new PhutilArgumentUsageException(
pht(
"Repository '%s' does not exist.",
$callsign));
}
$publisher->setRepositoryPHID($repository->getPHID());
}
$this->publishDocumentation($args->getArg('clean'), $publisher);
}

View file

@ -1913,7 +1913,25 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$this->delete();
$this->delete();
$books = id(new DivinerBookQuery())
->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($this->getPHID()))
->execute();
foreach ($books as $book) {
$engine->destroyObject($book);
}
$atoms = id(new DivinerAtomQuery())
->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($this->getPHID()))
->execute();
foreach ($atoms as $atom) {
$engine->destroyObject($atom);
}
$this->saveTransaction();
}