1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-24 20:49:06 +01:00

(stable) Promote 2019 Week 44

This commit is contained in:
epriestley 2019-11-03 18:06:52 -08:00
commit 7585b1212b
22 changed files with 696 additions and 185 deletions

View file

@ -9,10 +9,10 @@ return array(
'names' => array( 'names' => array(
'conpherence.pkg.css' => '3c8a0668', 'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf', 'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => '686ae87c', 'core.pkg.css' => '77de226f',
'core.pkg.js' => '6e5c894f', 'core.pkg.js' => '6e5c894f',
'differential.pkg.css' => '607c84be', 'differential.pkg.css' => '607c84be',
'differential.pkg.js' => 'a0212a0b', 'differential.pkg.js' => '1b97518d',
'diffusion.pkg.css' => '42c75c37', 'diffusion.pkg.css' => '42c75c37',
'diffusion.pkg.js' => 'a98c0bf7', 'diffusion.pkg.js' => 'a98c0bf7',
'maniphest.pkg.css' => '35995d6d', 'maniphest.pkg.css' => '35995d6d',
@ -30,7 +30,7 @@ return array(
'rsrc/css/aphront/notification.css' => '30240bd2', 'rsrc/css/aphront/notification.css' => '30240bd2',
'rsrc/css/aphront/panel-view.css' => '46923d46', 'rsrc/css/aphront/panel-view.css' => '46923d46',
'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf', 'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf',
'rsrc/css/aphront/table-view.css' => '5f13a9e4', 'rsrc/css/aphront/table-view.css' => '0bb61df1',
'rsrc/css/aphront/tokenizer.css' => 'b52d0668', 'rsrc/css/aphront/tokenizer.css' => 'b52d0668',
'rsrc/css/aphront/tooltip.css' => 'e3f2412f', 'rsrc/css/aphront/tooltip.css' => 'e3f2412f',
'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2', 'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2',
@ -428,7 +428,7 @@ return array(
'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68', 'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68',
'rsrc/js/application/releeph/releeph-request-state-change.js' => '9f081f05', 'rsrc/js/application/releeph/releeph-request-state-change.js' => '9f081f05',
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'aa3a100c', 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'aa3a100c',
'rsrc/js/application/repository/repository-crossreference.js' => 'c15122b4', 'rsrc/js/application/repository/repository-crossreference.js' => '1c95ea63',
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e5bdb730', 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e5bdb730',
'rsrc/js/application/search/behavior-reorder-queries.js' => 'b86f297f', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'b86f297f',
'rsrc/js/application/transactions/behavior-comment-actions.js' => '4dffaeb2', 'rsrc/js/application/transactions/behavior-comment-actions.js' => '4dffaeb2',
@ -535,7 +535,7 @@ return array(
'aphront-list-filter-view-css' => 'feb64255', 'aphront-list-filter-view-css' => 'feb64255',
'aphront-multi-column-view-css' => 'fbc00ba3', 'aphront-multi-column-view-css' => 'fbc00ba3',
'aphront-panel-view-css' => '46923d46', 'aphront-panel-view-css' => '46923d46',
'aphront-table-view-css' => '5f13a9e4', 'aphront-table-view-css' => '0bb61df1',
'aphront-tokenizer-control-css' => 'b52d0668', 'aphront-tokenizer-control-css' => 'b52d0668',
'aphront-tooltip-css' => 'e3f2412f', 'aphront-tooltip-css' => 'e3f2412f',
'aphront-typeahead-control-css' => '8779483d', 'aphront-typeahead-control-css' => '8779483d',
@ -682,7 +682,7 @@ return array(
'javelin-behavior-reorder-applications' => 'aa371860', 'javelin-behavior-reorder-applications' => 'aa371860',
'javelin-behavior-reorder-columns' => '8ac32fd9', 'javelin-behavior-reorder-columns' => '8ac32fd9',
'javelin-behavior-reorder-profile-menu-items' => 'e5bdb730', 'javelin-behavior-reorder-profile-menu-items' => 'e5bdb730',
'javelin-behavior-repository-crossreference' => 'c15122b4', 'javelin-behavior-repository-crossreference' => '1c95ea63',
'javelin-behavior-scrollbar' => '92388bae', 'javelin-behavior-scrollbar' => '92388bae',
'javelin-behavior-search-reorder-queries' => 'b86f297f', 'javelin-behavior-search-reorder-queries' => 'b86f297f',
'javelin-behavior-select-content' => 'e8240b50', 'javelin-behavior-select-content' => 'e8240b50',
@ -1034,6 +1034,12 @@ return array(
'javelin-install', 'javelin-install',
'javelin-util', 'javelin-util',
), ),
'1c95ea63' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-uri',
),
'1cab0e9a' => array( '1cab0e9a' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-dom', 'javelin-dom',
@ -1977,12 +1983,6 @@ return array(
'c03f2fb4' => array( 'c03f2fb4' => array(
'javelin-install', 'javelin-install',
), ),
'c15122b4' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-uri',
),
'c2c500a7' => array( 'c2c500a7' => array(
'javelin-install', 'javelin-install',
'javelin-dom', 'javelin-dom',

View file

@ -0,0 +1,4 @@
<?php
PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery(
'PhabricatorRepositoryQuery');

View file

@ -1338,6 +1338,8 @@ phutil_register_library_map(array(
'HarbormasterArcLintBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php', 'HarbormasterArcLintBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php',
'HarbormasterArcUnitBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcUnitBuildStepImplementation.php', 'HarbormasterArcUnitBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcUnitBuildStepImplementation.php',
'HarbormasterArtifact' => 'applications/harbormaster/artifact/HarbormasterArtifact.php', 'HarbormasterArtifact' => 'applications/harbormaster/artifact/HarbormasterArtifact.php',
'HarbormasterArtifactSearchConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterArtifactSearchConduitAPIMethod.php',
'HarbormasterArtifactSearchEngine' => 'applications/harbormaster/query/HarbormasterArtifactSearchEngine.php',
'HarbormasterAutotargetsTestCase' => 'applications/harbormaster/__tests__/HarbormasterAutotargetsTestCase.php', 'HarbormasterAutotargetsTestCase' => 'applications/harbormaster/__tests__/HarbormasterAutotargetsTestCase.php',
'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php', 'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php',
'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php', 'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php',
@ -4650,6 +4652,7 @@ phutil_register_library_map(array(
'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php', 'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php',
'PhabricatorSearchIndexVersion' => 'applications/search/storage/PhabricatorSearchIndexVersion.php', 'PhabricatorSearchIndexVersion' => 'applications/search/storage/PhabricatorSearchIndexVersion.php',
'PhabricatorSearchIndexVersionDestructionEngineExtension' => 'applications/search/engineextension/PhabricatorSearchIndexVersionDestructionEngineExtension.php', 'PhabricatorSearchIndexVersionDestructionEngineExtension' => 'applications/search/engineextension/PhabricatorSearchIndexVersionDestructionEngineExtension.php',
'PhabricatorSearchIntField' => 'applications/search/field/PhabricatorSearchIntField.php',
'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php', 'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php',
'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php', 'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php',
'PhabricatorSearchManagementNgramsWorkflow' => 'applications/search/management/PhabricatorSearchManagementNgramsWorkflow.php', 'PhabricatorSearchManagementNgramsWorkflow' => 'applications/search/management/PhabricatorSearchManagementNgramsWorkflow.php',
@ -7369,6 +7372,8 @@ phutil_register_library_map(array(
'HarbormasterArcLintBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterArcLintBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterArcUnitBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterArcUnitBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterArtifact' => 'Phobject', 'HarbormasterArtifact' => 'Phobject',
'HarbormasterArtifactSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'HarbormasterArtifactSearchEngine' => 'PhabricatorApplicationSearchEngine',
'HarbormasterAutotargetsTestCase' => 'PhabricatorTestCase', 'HarbormasterAutotargetsTestCase' => 'PhabricatorTestCase',
'HarbormasterBuild' => array( 'HarbormasterBuild' => array(
'HarbormasterDAO', 'HarbormasterDAO',
@ -7384,6 +7389,7 @@ phutil_register_library_map(array(
'HarbormasterDAO', 'HarbormasterDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
'PhabricatorConduitResultInterface',
), ),
'HarbormasterBuildArtifactPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildArtifactPHIDType' => 'PhabricatorPHIDType',
'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@ -11268,6 +11274,7 @@ phutil_register_library_map(array(
'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchIndexVersion' => 'PhabricatorSearchDAO', 'PhabricatorSearchIndexVersion' => 'PhabricatorSearchDAO',
'PhabricatorSearchIndexVersionDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorSearchIndexVersionDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
'PhabricatorSearchIntField' => 'PhabricatorSearchField',
'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow',
'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow',
'PhabricatorSearchManagementNgramsWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementNgramsWorkflow' => 'PhabricatorSearchManagementWorkflow',

View file

@ -44,15 +44,6 @@ final class DifferentialRevisionPHIDType extends PhabricatorPHIDType {
if ($revision->isClosed()) { if ($revision->isClosed()) {
$handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED);
} }
$icon = $revision->getStatusIcon();
$color = $revision->getStatusIconColor();
$name = $revision->getStatusDisplayName();
$handle
->setStateIcon($icon)
->setStateColor($color)
->setStateName($name);
} }
} }

View file

@ -26,20 +26,45 @@ final class DiffusionHovercardEngineExtension
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$author_phid = $commit->getAuthorPHID(); $commit = id(new DiffusionCommitQuery())
if ($author_phid) { ->setViewer($viewer)
$author = $viewer->renderHandle($author_phid); ->needIdentities(true)
} else { ->needCommitData(true)
$commit_data = $commit->loadCommitData(); ->withPHIDs(array($commit->getPHID()))
$author = phutil_tag('em', array(), $commit_data->getAuthorName()); ->executeOne();
if (!$commit) {
return;
} }
$author_phid = $commit->getAuthorDisplayPHID();
$committer_phid = $commit->getCommitterDisplayPHID();
$repository_phid = $commit->getRepository()->getPHID();
$phids = array();
$phids[] = $author_phid;
$phids[] = $committer_phid;
$phids[] = $repository_phid;
$handles = $viewer->loadHandles($phids);
$hovercard->setTitle($handle->getName()); $hovercard->setTitle($handle->getName());
$hovercard->setDetail($commit->getSummary()); $hovercard->setDetail($commit->getSummary());
$repository = $handles[$repository_phid]->renderLink();
$hovercard->addField(pht('Repository'), $repository);
$author = $handles[$author_phid]->renderLink();
if ($author_phid) {
$hovercard->addField(pht('Author'), $author); $hovercard->addField(pht('Author'), $author);
$hovercard->addField(pht('Date'), }
phabricator_date($commit->getEpoch(), $viewer));
if ($committer_phid && ($committer_phid !== $author_phid)) {
$committer = $handles[$committer_phid]->renderLink();
$hovercard->addField(pht('Committer'), $committer);
}
$date = phabricator_date($commit->getEpoch(), $viewer);
$hovercard->addField(pht('Date'), $date);
if (!$commit->isAuditStatusNoAudit()) { if (!$commit->isAuditStatusNoAudit()) {
$status = $commit->getAuditStatusObject(); $status = $commit->getAuditStatusObject();

View file

@ -29,6 +29,7 @@ final class PhabricatorFactChartFunction
$key_id = id(new PhabricatorFactKeyDimension()) $key_id = id(new PhabricatorFactKeyDimension())
->newDimensionID($fact->getKey()); ->newDimensionID($fact->getKey());
if (!$key_id) { if (!$key_id) {
$this->map = array();
return; return;
} }

View file

@ -0,0 +1,18 @@
<?php
final class HarbormasterArtifactSearchConduitAPIMethod
extends PhabricatorSearchEngineAPIMethod {
public function getAPIMethodName() {
return 'harbormaster.artifact.search';
}
public function newSearchEngine() {
return new HarbormasterArtifactSearchEngine();
}
public function getMethodSummary() {
return pht('Query information about build artifacts.');
}
}

View file

@ -0,0 +1,93 @@
<?php
final class HarbormasterArtifactSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Harbormaster Artifacts');
}
public function getApplicationClassName() {
return 'PhabricatorHarbormasterApplication';
}
public function newQuery() {
return new HarbormasterBuildArtifactQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorPHIDsSearchField())
->setLabel(pht('Targets'))
->setKey('buildTargetPHIDs')
->setAliases(
array(
'buildTargetPHID',
'buildTargets',
'buildTarget',
'targetPHIDs',
'targetPHID',
'targets',
'target',
))
->setDescription(
pht('Search for artifacts attached to particular build targets.')),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['buildTargetPHIDs']) {
$query->withBuildTargetPHIDs($map['buildTargetPHIDs']);
}
return $query;
}
protected function getURI($path) {
return '/harbormaster/artifact/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'all' => pht('All Artifacts'),
);
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $artifacts,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($artifacts, 'HarbormasterBuildArtifact');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
foreach ($artifacts as $artifact) {
$id = $artifact->getID();
$item = id(new PHUIObjectItemView())
->setObjectName(pht('Artifact %d', $id));
$list->addItem($item);
}
return id(new PhabricatorApplicationSearchResultView())
->setObjectList($list)
->setNoDataString(pht('No artifacts found.'));
}
}

View file

@ -4,7 +4,8 @@ final class HarbormasterBuildArtifact
extends HarbormasterDAO extends HarbormasterDAO
implements implements
PhabricatorPolicyInterface, PhabricatorPolicyInterface,
PhabricatorDestructibleInterface { PhabricatorDestructibleInterface,
PhabricatorConduitResultInterface {
protected $buildTargetPHID; protected $buildTargetPHID;
protected $artifactType; protected $artifactType;
@ -18,6 +19,7 @@ final class HarbormasterBuildArtifact
public static function initializeNewBuildArtifact( public static function initializeNewBuildArtifact(
HarbormasterBuildTarget $build_target) { HarbormasterBuildTarget $build_target) {
return id(new HarbormasterBuildArtifact()) return id(new HarbormasterBuildArtifact())
->attachBuildTarget($build_target) ->attachBuildTarget($build_target)
->setBuildTargetPHID($build_target->getPHID()); ->setBuildTargetPHID($build_target->getPHID());
@ -53,9 +55,8 @@ final class HarbormasterBuildArtifact
) + parent::getConfiguration(); ) + parent::getConfiguration();
} }
public function generatePHID() { public function getPHIDType() {
return PhabricatorPHID::generateNewPHID( return HarbormasterBuildArtifactPHIDType::TYPECONST;
HarbormasterBuildArtifactPHIDType::TYPECONST);
} }
public function attachBuildTarget(HarbormasterBuildTarget $build_target) { public function attachBuildTarget(HarbormasterBuildTarget $build_target) {
@ -147,7 +148,8 @@ final class HarbormasterBuildArtifact
} }
public function describeAutomaticCapability($capability) { public function describeAutomaticCapability($capability) {
return pht('Users must be able to see a buildable to see its artifacts.'); return pht(
'Users must be able to see a build target to see its artifacts.');
} }
@ -165,4 +167,40 @@ final class HarbormasterBuildArtifact
$this->saveTransaction(); $this->saveTransaction();
} }
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('buildTargetPHID')
->setType('phid')
->setDescription(pht('The build target this artifact is attached to.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('artifactType')
->setType('string')
->setDescription(pht('The artifact type.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('artifactKey')
->setType('string')
->setDescription(pht('The artifact key.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('isReleased')
->setType('bool')
->setDescription(pht('True if this artifact has been released.')),
);
}
public function getFieldValuesForConduit() {
return array(
'buildTargetPHID' => $this->getBuildTargetPHID(),
'artifactType' => $this->getArtifactType(),
'artifactKey' => $this->getArtifactKey(),
'isReleased' => (bool)$this->getIsReleased(),
);
}
public function getConduitSearchAttachments() {
return array();
}
} }

View file

@ -179,11 +179,14 @@ final class ManiphestTaskDetailController extends ManiphestController {
->addTabGroup($tab_group); ->addTabGroup($tab_group);
} }
$changes_view = $this->newChangesView($task, $edges);
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())
->setHeader($header) ->setHeader($header)
->setCurtain($curtain) ->setCurtain($curtain)
->setMainColumn( ->setMainColumn(
array( array(
$changes_view,
$tab_view, $tab_view,
$timeline, $timeline,
$comment_view, $comment_view,
@ -395,58 +398,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
$source)); $source));
} }
$edge_types = array(
ManiphestTaskHasRevisionEdgeType::EDGECONST
=> pht('Differential Revisions'),
);
$revisions_commits = array();
$commit_phids = array_keys(
$edges[ManiphestTaskHasCommitEdgeType::EDGECONST]);
if ($commit_phids) {
$commit_drev = DiffusionCommitHasRevisionEdgeType::EDGECONST;
$drev_edges = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($commit_phids)
->withEdgeTypes(array($commit_drev))
->execute();
foreach ($commit_phids as $phid) {
$revisions_commits[$phid] = $handles->renderHandle($phid)
->setShowHovercard(true)
->setShowStateIcon(true);
$revision_phid = key($drev_edges[$phid][$commit_drev]);
$revision_handle = $handles->getHandleIfExists($revision_phid);
if ($revision_handle) {
$task_drev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
unset($edges[$task_drev][$revision_phid]);
$revisions_commits[$phid] = hsprintf(
'%s / %s',
$revision_handle->renderHovercardLink($revision_handle->getName()),
$revisions_commits[$phid]);
}
}
}
foreach ($edge_types as $edge_type => $edge_name) {
if (!$edges[$edge_type]) {
continue;
}
$edge_handles = $viewer->loadHandles(array_keys($edges[$edge_type]));
$edge_list = $edge_handles->renderList()
->setShowStateIcons(true);
$view->addProperty($edge_name, $edge_list);
}
if ($revisions_commits) {
$view->addProperty(
pht('Commits'),
phutil_implode_html(phutil_tag('br'), $revisions_commits));
}
$field_list->appendFieldsToPropertyList( $field_list->appendFieldsToPropertyList(
$task, $task,
$viewer, $viewer,
@ -596,5 +547,291 @@ final class ManiphestTaskDetailController extends ManiphestController {
return $handles->newSublist($phids); return $handles->newSublist($phids);
} }
private function newChangesView(ManiphestTask $task, array $edges) {
$viewer = $this->getViewer();
$revision_type = ManiphestTaskHasRevisionEdgeType::EDGECONST;
$commit_type = ManiphestTaskHasCommitEdgeType::EDGECONST;
$revision_phids = idx($edges, $revision_type, array());
$revision_phids = array_keys($revision_phids);
$revision_phids = array_fuse($revision_phids);
$commit_phids = idx($edges, $commit_type, array());
$commit_phids = array_keys($commit_phids);
$commit_phids = array_fuse($commit_phids);
if (!$revision_phids && !$commit_phids) {
return null;
}
if ($commit_phids) {
$link_type = DiffusionCommitHasRevisionEdgeType::EDGECONST;
$link_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($commit_phids)
->withEdgeTypes(array($link_type));
$link_query->execute();
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withPHIDs($commit_phids)
->execute();
$commits = mpull($commits, null, 'getPHID');
} else {
$commits = array();
}
if ($revision_phids) {
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withPHIDs($revision_phids)
->execute();
$revisions = mpull($revisions, null, 'getPHID');
} else {
$revisions = array();
}
$handle_phids = array();
$any_linked = false;
$any_status = false;
$idx = 0;
$objects = array();
foreach ($commit_phids as $commit_phid) {
$handle_phids[] = $commit_phid;
$link_phids = $link_query->getDestinationPHIDs(array($commit_phid));
foreach ($link_phids as $link_phid) {
$handle_phids[] = $link_phid;
unset($revision_phids[$link_phid]);
$any_linked = true;
}
$commit = idx($commits, $commit_phid);
if ($commit) {
$repository_phid = $commit->getRepository()->getPHID();
$handle_phids[] = $repository_phid;
} else {
$repository_phid = null;
}
$status_view = null;
if ($commit) {
$status = $commit->getAuditStatusObject();
if (!$status->isNoAudit()) {
$status_view = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setIcon($status->getIcon())
->setColor($status->getColor())
->setName($status->getName());
}
}
$object_link = null;
if ($commit) {
$commit_monogram = $commit->getDisplayName();
$commit_monogram = phutil_tag(
'span',
array(
'class' => 'object-name',
),
$commit_monogram);
$commit_link = javelin_tag(
'a',
array(
'href' => $commit->getURI(),
'sigil' => 'hovercard',
'meta' => array(
'hoverPHID' => $commit->getPHID(),
),
),
$commit->getSummary());
$object_link = array(
$commit_monogram,
' ',
$commit_link,
);
}
$objects[] = array(
'objectPHID' => $commit_phid,
'objectLink' => $object_link,
'repositoryPHID' => $repository_phid,
'revisionPHIDs' => $link_phids,
'status' => $status_view,
'order' => id(new PhutilSortVector())
->addInt($repository_phid ? 1 : 0)
->addString((string)$repository_phid)
->addInt(1)
->addInt($idx++),
);
}
foreach ($revision_phids as $revision_phid) {
$handle_phids[] = $revision_phid;
$revision = idx($revisions, $revision_phid);
if ($revision) {
$repository_phid = $revision->getRepositoryPHID();
$handle_phids[] = $repository_phid;
} else {
$repository_phid = null;
}
if ($revision) {
$icon = $revision->getStatusIcon();
$color = $revision->getStatusIconColor();
$name = $revision->getStatusDisplayName();
$status_view = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setIcon($icon)
->setColor($color)
->setName($name);
} else {
$status_view = null;
}
$object_link = null;
if ($revision) {
$revision_monogram = $revision->getMonogram();
$revision_monogram = phutil_tag(
'span',
array(
'class' => 'object-name',
),
$revision_monogram);
$revision_link = javelin_tag(
'a',
array(
'href' => $revision->getURI(),
'sigil' => 'hovercard',
'meta' => array(
'hoverPHID' => $revision->getPHID(),
),
),
$revision->getTitle());
$object_link = array(
$revision_monogram,
' ',
$revision_link,
);
}
$objects[] = array(
'objectPHID' => $revision_phid,
'objectLink' => $object_link,
'repositoryPHID' => $repository_phid,
'revisionPHIDs' => array(),
'status' => $status_view,
'order' => id(new PhutilSortVector())
->addInt($repository_phid ? 1 : 0)
->addString((string)$repository_phid)
->addInt(0)
->addInt($idx++),
);
}
$handles = $viewer->loadHandles($handle_phids);
$order = ipull($objects, 'order');
$order = msortv($order, 'getSelf');
$objects = array_select_keys($objects, array_keys($order));
$last_repository = false;
$rows = array();
$rowd = array();
foreach ($objects as $object) {
$repository_phid = $object['repositoryPHID'];
if ($repository_phid !== $last_repository) {
$repository_link = null;
if ($repository_phid) {
$repository_handle = $handles[$repository_phid];
$rows[] = array(
$repository_handle->renderLink(),
);
$rowd[] = true;
}
$last_repository = $repository_phid;
}
$object_phid = $object['objectPHID'];
$handle = $handles[$object_phid];
$object_link = $object['objectLink'];
if ($object_link === null) {
$object_link = $handle->renderLink();
}
$object_icon = id(new PHUIIconView())
->setIcon($handle->getIcon());
$status_view = $object['status'];
if ($status_view) {
$any_status = true;
}
$revision_tags = array();
foreach ($object['revisionPHIDs'] as $link_phid) {
$revision_handle = $handles[$link_phid];
$revision_name = $revision_handle->getName();
$revision_tags[] = $revision_handle
->renderHovercardLink($revision_name);
}
$revision_tags = phutil_implode_html(
phutil_tag('br'),
$revision_tags);
$rowd[] = false;
$rows[] = array(
$object_icon,
$status_view,
$revision_tags,
$object_link,
);
}
$changes_table = id(new AphrontTableView($rows))
->setNoDataString(pht('This task has no related commits or revisions.'))
->setRowDividers($rowd)
->setColumnClasses(
array(
'indent center',
null,
null,
'wide pri object-link',
))
->setColumnVisibility(
array(
true,
$any_status,
$any_linked,
true,
))
->setDeviceVisibility(
array(
false,
$any_status,
false,
true,
));
$changes_header = id(new PHUIHeaderView())
->setHeader(pht('Revisions and Commits'));
$changes_view = id(new PHUIObjectBoxView())
->setHeader($changes_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($changes_table);
return $changes_view;
}
} }

View file

@ -33,10 +33,6 @@ final class PhabricatorObjectHandle
private $commandLineObjectName; private $commandLineObjectName;
private $mailStampName; private $mailStampName;
private $stateIcon;
private $stateColor;
private $stateName;
public function setIcon($icon) { public function setIcon($icon) {
$this->icon = $icon; $this->icon = $icon;
return $this; return $this;
@ -299,55 +295,6 @@ final class PhabricatorObjectHandle
return $this->complete; return $this->complete;
} }
public function setStateIcon($state_icon) {
$this->stateIcon = $state_icon;
return $this;
}
public function getStateIcon() {
return $this->stateIcon;
}
public function setStateColor($state_color) {
$this->stateColor = $state_color;
return $this;
}
public function getStateColor() {
return $this->stateColor;
}
public function setStateName($state_name) {
$this->stateName = $state_name;
return $this;
}
public function getStateName() {
return $this->stateName;
}
public function renderStateIcon() {
$icon = $this->getStateIcon();
if ($icon === null) {
$icon = 'fa-question-circle-o';
}
$color = $this->getStateColor();
$name = $this->getStateName();
if ($name === null) {
$name = pht('Unknown');
}
return id(new PHUIIconView())
->setIcon($icon, $color)
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => $name,
));
}
public function renderLink($name = null) { public function renderLink($name = null) {
return $this->renderLinkWithAttributes($name, array()); return $this->renderLinkWithAttributes($name, array());
} }

View file

@ -13,7 +13,6 @@ final class PHUIHandleListView
private $handleList; private $handleList;
private $asInline; private $asInline;
private $asText; private $asText;
private $showStateIcons;
private $glyphLimit; private $glyphLimit;
public function setHandleList(PhabricatorHandleList $list) { public function setHandleList(PhabricatorHandleList $list) {
@ -39,15 +38,6 @@ final class PHUIHandleListView
return $this->asText; return $this->asText;
} }
public function setShowStateIcons($show_state_icons) {
$this->showStateIcons = $show_state_icons;
return $this;
}
public function getShowStateIcons() {
return $this->showStateIcons;
}
public function setGlyphLimit($glyph_limit) { public function setGlyphLimit($glyph_limit) {
$this->glyphLimit = $glyph_limit; $this->glyphLimit = $glyph_limit;
return $this; return $this;
@ -70,7 +60,6 @@ final class PHUIHandleListView
protected function getTagContent() { protected function getTagContent() {
$list = $this->handleList; $list = $this->handleList;
$show_state_icons = $this->getShowStateIcons();
$glyph_limit = $this->getGlyphLimit(); $glyph_limit = $this->getGlyphLimit();
$items = array(); $items = array();
@ -79,10 +68,6 @@ final class PHUIHandleListView
->setShowHovercard(true) ->setShowHovercard(true)
->setAsText($this->getAsText()); ->setAsText($this->getAsText());
if ($show_state_icons) {
$view->setShowStateIcon(true);
}
if ($glyph_limit) { if ($glyph_limit) {
$view->setGlyphLimit($glyph_limit); $view->setGlyphLimit($glyph_limit);
} }

View file

@ -17,7 +17,6 @@ final class PHUIHandleView
private $asText; private $asText;
private $useShortName; private $useShortName;
private $showHovercard; private $showHovercard;
private $showStateIcon;
private $glyphLimit; private $glyphLimit;
public function setHandleList(PhabricatorHandleList $list) { public function setHandleList(PhabricatorHandleList $list) {
@ -50,15 +49,6 @@ final class PHUIHandleView
return $this; return $this;
} }
public function setShowStateIcon($show_state_icon) {
$this->showStateIcon = $show_state_icon;
return $this;
}
public function getShowStateIcon() {
return $this->showStateIcon;
}
public function setGlyphLimit($glyph_limit) { public function setGlyphLimit($glyph_limit) {
$this->glyphLimit = $glyph_limit; $this->glyphLimit = $glyph_limit;
return $this; return $this;
@ -104,11 +94,6 @@ final class PHUIHandleView
$link = $handle->renderLink($name); $link = $handle->renderLink($name);
} }
if ($this->showStateIcon) {
$icon = $handle->renderStateIcon();
$link = array($icon, ' ', $link);
}
return $link; return $link;
} }

View file

@ -53,7 +53,11 @@ final class PhabricatorProjectBurndownChartEngine
$open_function = $this->newFunction( $open_function = $this->newFunction(
array( array(
'accumulate', 'accumulate',
array(
'sum',
array('fact', 'tasks.open-count.create'), array('fact', 'tasks.open-count.create'),
array('fact', 'tasks.open-count.status'),
),
)); ));
$closed_function = $this->newFunction( $closed_function = $this->newFunction(

View file

@ -65,6 +65,35 @@ final class PhabricatorProjectSearchEngine
pht( pht(
'Pass true to find only milestones, or false to omit '. 'Pass true to find only milestones, or false to omit '.
'milestones.')), 'milestones.')),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Root Projects'))
->setKey('isRoot')
->setOptions(
pht('(Show All)'),
pht('Show Only Root Projects'),
pht('Hide Root Projects'))
->setDescription(
pht(
'Pass true to find only root projects, or false to omit '.
'root projects.')),
id(new PhabricatorSearchIntField())
->setLabel(pht('Minimum Depth'))
->setKey('minDepth')
->setIsHidden(true)
->setDescription(
pht(
'Find projects with a given minimum depth. Root projects '.
'have depth 0, their immediate children have depth 1, and '.
'so on.')),
id(new PhabricatorSearchIntField())
->setLabel(pht('Maximum Depth'))
->setKey('maxDepth')
->setIsHidden(true)
->setDescription(
pht(
'Find projects with a given maximum depth. Root projects '.
'have depth 0, their immediate children have depth 1, and '.
'so on.')),
id(new PhabricatorSearchDatasourceField()) id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Subtypes')) ->setLabel(pht('Subtypes'))
->setKey('subtypes') ->setKey('subtypes')
@ -137,6 +166,42 @@ final class PhabricatorProjectSearchEngine
$query->withIsMilestone($map['isMilestone']); $query->withIsMilestone($map['isMilestone']);
} }
$min_depth = $map['minDepth'];
$max_depth = $map['maxDepth'];
if ($min_depth !== null || $max_depth !== null) {
if ($min_depth !== null && $max_depth !== null) {
if ($min_depth > $max_depth) {
throw new Exception(
pht(
'Search constraint "minDepth" must be no larger than '.
'search constraint "maxDepth".'));
}
}
}
if ($map['isRoot'] !== null) {
if ($map['isRoot']) {
if ($max_depth === null) {
$max_depth = 0;
} else {
$max_depth = min(0, $max_depth);
}
$query->withDepthBetween(null, 0);
} else {
if ($min_depth === null) {
$min_depth = 1;
} else {
$min_depth = max($min_depth, 1);
}
}
}
if ($min_depth !== null || $max_depth !== null) {
$query->withDepthBetween($min_depth, $max_depth);
}
if ($map['parentPHIDs']) { if ($map['parentPHIDs']) {
$query->withParentProjectPHIDs($map['parentPHIDs']); $query->withParentProjectPHIDs($map['parentPHIDs']);
} }

View file

@ -130,10 +130,35 @@ final class PhabricatorRepositoryURINormalizer extends Phobject {
$domain = $uri->getDomain(); $domain = $uri->getDomain();
if (!strlen($domain)) { if (!strlen($domain)) {
$domain = '<void>'; return '<void>';
} }
return phutil_utf8_strtolower($domain); $domain = phutil_utf8_strtolower($domain);
// See T13435. If the domain for a repository URI is same as the install
// base URI, store it as a "<base-uri>" token instead of the actual domain
// so that the index does not fall out of date if the install moves.
$base_uri = PhabricatorEnv::getURI('/');
$base_uri = new PhutilURI($base_uri);
$base_domain = $base_uri->getDomain();
$base_domain = phutil_utf8_strtolower($base_domain);
if ($domain === $base_domain) {
return '<base-uri>';
}
// Likewise, store a token for the "SSH Host" domain so it can be changed
// without requiring an index rebuild.
$ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host');
if (strlen($ssh_host)) {
$ssh_host = phutil_utf8_strtolower($ssh_host);
if ($domain === $ssh_host) {
return '<ssh-host>';
}
}
return $domain;
} }

View file

@ -31,6 +31,36 @@ final class PhabricatorRepositoryURINormalizerTestCase
} }
} }
public function testDomainURINormalizer() {
$base_domain = 'base.phabricator.example.com';
$ssh_domain = 'ssh.phabricator.example.com';
$env = PhabricatorEnv::beginScopedEnv();
$env->overrideEnvConfig('phabricator.base-uri', 'http://'.$base_domain);
$env->overrideEnvConfig('diffusion.ssh-host', $ssh_domain);
$cases = array(
'/' => '<void>',
'/path/to/local/repo.git' => '<void>',
'ssh://user@domain.com/path.git' => 'domain.com',
'ssh://user@DOMAIN.COM/path.git' => 'domain.com',
'http://'.$base_domain.'/diffusion/X/' => '<base-uri>',
'ssh://'.$ssh_domain.'/diffusion/X/' => '<ssh-host>',
'git@'.$ssh_domain.':bananas.git' => '<ssh-host>',
);
$type_git = PhabricatorRepositoryURINormalizer::TYPE_GIT;
foreach ($cases as $input => $expect) {
$normal = new PhabricatorRepositoryURINormalizer($type_git, $input);
$this->assertEqual(
$expect,
$normal->getNormalizedDomain(),
pht('Normalized domain for "%s".', $input));
}
}
public function testSVNURINormalizer() { public function testSVNURINormalizer() {
$cases = array( $cases = array(
'file:///path/to/repo' => 'path/to/repo', 'file:///path/to/repo' => 'path/to/repo',

View file

@ -81,16 +81,6 @@ final class PhabricatorRepositoryCommitPHIDType extends PhabricatorPHIDType {
$handle->setFullName($full_name); $handle->setFullName($full_name);
$handle->setURI($commit->getURI()); $handle->setURI($commit->getURI());
$handle->setTimestamp($commit->getEpoch()); $handle->setTimestamp($commit->getEpoch());
$status = $commit->getAuditStatusObject();
$icon = $status->getIcon();
$color = $status->getColor();
$name = $status->getName();
$handle
->setStateIcon($icon)
->setStateColor($color)
->setStateName($name);
} }
} }

View file

@ -0,0 +1,22 @@
<?php
final class PhabricatorSearchIntField
extends PhabricatorSearchField {
protected function getDefaultValue() {
return null;
}
protected function getValueFromRequest(AphrontRequest $request, $key) {
return $request->getInt($key);
}
protected function newControl() {
return new AphrontFormTextControl();
}
protected function newConduitParameterType() {
return new ConduitIntParameterType();
}
}

View file

@ -24,6 +24,8 @@ final class AphrontTableView extends AphrontView {
protected $sortValues = array(); protected $sortValues = array();
private $deviceReadyTable; private $deviceReadyTable;
private $rowDividers = array();
public function __construct(array $data) { public function __construct(array $data) {
$this->data = $data; $this->data = $data;
} }
@ -53,6 +55,11 @@ final class AphrontTableView extends AphrontView {
return $this; return $this;
} }
public function setRowDividers(array $dividers) {
$this->rowDividers = $dividers;
return $this;
}
public function setNoDataString($no_data_string) { public function setNoDataString($no_data_string) {
$this->noDataString = $no_data_string; $this->noDataString = $no_data_string;
return $this; return $this;
@ -258,10 +265,15 @@ final class AphrontTableView extends AphrontView {
} }
} }
$dividers = $this->rowDividers;
$data = $this->data; $data = $this->data;
if ($data) { if ($data) {
$row_num = 0; $row_num = 0;
$row_idx = 0;
foreach ($data as $row) { foreach ($data as $row) {
$is_divider = !empty($dividers[$row_num]);
$row_size = count($row); $row_size = count($row);
while (count($row) > count($col_classes)) { while (count($row) > count($col_classes)) {
$col_classes[] = null; $col_classes[] = null;
@ -289,6 +301,18 @@ final class AphrontTableView extends AphrontView {
$class = trim($class.' '.$this->cellClasses[$row_num][$col_num]); $class = trim($class.' '.$this->cellClasses[$row_num][$col_num]);
} }
if ($is_divider) {
$tr[] = phutil_tag(
'td',
array(
'class' => 'row-divider',
'colspan' => count($visibility),
),
$value);
$row_idx = -1;
break;
}
$tr[] = phutil_tag( $tr[] = phutil_tag(
'td', 'td',
array( array(
@ -299,7 +323,7 @@ final class AphrontTableView extends AphrontView {
} }
$class = idx($this->rowClasses, $row_num); $class = idx($this->rowClasses, $row_num);
if ($this->zebraStripes && ($row_num % 2)) { if ($this->zebraStripes && ($row_idx % 2)) {
if ($class !== null) { if ($class !== null) {
$class = 'alt alt-'.$class; $class = 'alt alt-'.$class;
} else { } else {
@ -309,6 +333,7 @@ final class AphrontTableView extends AphrontView {
$table[] = phutil_tag('tr', array('class' => $class), $tr); $table[] = phutil_tag('tr', array('class' => $class), $tr);
++$row_num; ++$row_num;
++$row_idx;
} }
} else { } else {
$colspan = max(count(array_filter($visibility)), 1); $colspan = max(count(array_filter($visibility)), 1);

View file

@ -55,6 +55,16 @@
background-color: {$lightbluebackground}; background-color: {$lightbluebackground};
} }
.aphront-table-view td.row-divider {
background-color: {$bluebackground};
font-weight: bold;
padding: 8px 12px;
}
.aphront-table-view td.indent {
padding-left: 24px;
}
.aphront-table-view th { .aphront-table-view th {
border-bottom: 1px solid {$thinblueborder}; border-bottom: 1px solid {$thinblueborder};
} }

View file

@ -152,7 +152,16 @@ JX.behavior('repository-crossreference', function(config, statics) {
query.char = char; query.char = char;
} }
var uri = JX.$U('/diffusion/symbol/' + symbol + '/'); var uri_symbol = symbol;
// In some cases, lexers may include whitespace in symbol tags. Trim it,
// since symbols with semantic whitespace aren't supported.
uri_symbol = uri_symbol.trim();
// See T13437. Symbols like "#define" need to be encoded.
uri_symbol = encodeURIComponent(uri_symbol);
var uri = JX.$U('/diffusion/symbol/' + uri_symbol + '/');
uri.addQueryParams(query); uri.addQueryParams(query);
window.open(uri.toString()); window.open(uri.toString());