1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-03-14 13:24:57 +01:00

(stable) Promote 2018 Week 14

This commit is contained in:
epriestley 2018-04-07 17:28:17 -07:00
commit fba35975e7
44 changed files with 1307 additions and 465 deletions

View file

@ -9,7 +9,7 @@ return array(
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => '1dd5fa4b',
'core.pkg.css' => '49b87886',
'core.pkg.js' => '1ea38af8',
'differential.pkg.css' => '113e692c',
'differential.pkg.js' => 'f6d809c0',
@ -132,7 +132,7 @@ return array(
'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77',
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => '08f4ccc3',
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '6ae18df0',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'ae1404ba',
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
'rsrc/css/phui/phui-action-list.css' => '0bcd9a45',
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
@ -158,7 +158,7 @@ return array(
'rsrc/css/phui/phui-header-view.css' => '31dc6c72',
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
'rsrc/css/phui/phui-icon.css' => '5c4a5de6',
'rsrc/css/phui/phui-icon.css' => 'cf24ceec',
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
'rsrc/css/phui/phui-info-view.css' => 'e929f98c',
'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0',
@ -833,7 +833,7 @@ return array(
'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'f0592bcf',
'phui-icon-set-selector-css' => '87db8fee',
'phui-icon-view-css' => '5c4a5de6',
'phui-icon-view-css' => 'cf24ceec',
'phui-image-mask-css' => 'a8498f9c',
'phui-info-view-css' => 'e929f98c',
'phui-inline-comment-view-css' => '65ae3bc2',
@ -846,7 +846,7 @@ return array(
'phui-oi-color-css' => 'cd2b9b77',
'phui-oi-drag-ui-css' => '08f4ccc3',
'phui-oi-flush-ui-css' => '9d9685d6',
'phui-oi-list-view-css' => '6ae18df0',
'phui-oi-list-view-css' => 'ae1404ba',
'phui-oi-simple-ui-css' => 'a8beebea',
'phui-pager-css' => 'edcbc226',
'phui-pinboard-view-css' => '2495140e',

View file

@ -0,0 +1,20 @@
<?php
$table = new DifferentialRevision();
$conn = $table->establishConnection('w');
$drafts = $table->loadAllWhere(
'status = %s',
DifferentialRevisionStatus::DRAFT);
foreach ($drafts as $draft) {
$properties = $draft->getProperties();
$properties[DifferentialRevision::PROPERTY_SHOULD_BROADCAST] = false;
queryfx(
$conn,
'UPDATE %T SET properties = %s WHERE id = %d',
id(new DifferentialRevision())->getTableName(),
phutil_json_encode($properties),
$draft->getID());
}

View file

@ -380,6 +380,7 @@ phutil_register_library_map(array(
'DifferentialBlockHeraldAction' => 'applications/differential/herald/DifferentialBlockHeraldAction.php',
'DifferentialBlockingReviewerDatasource' => 'applications/differential/typeahead/DifferentialBlockingReviewerDatasource.php',
'DifferentialBranchField' => 'applications/differential/customfield/DifferentialBranchField.php',
'DifferentialBuildableEngine' => 'applications/differential/harbormaster/DifferentialBuildableEngine.php',
'DifferentialChangeDetailMailView' => 'applications/differential/mail/DifferentialChangeDetailMailView.php',
'DifferentialChangeHeraldFieldGroup' => 'applications/differential/herald/DifferentialChangeHeraldFieldGroup.php',
'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php',
@ -388,6 +389,7 @@ phutil_register_library_map(array(
'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php',
'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php',
'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php',
'DifferentialChangesetListController' => 'applications/differential/controller/DifferentialChangesetListController.php',
'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php',
'DifferentialChangesetOneUpMailRenderer' => 'applications/differential/render/DifferentialChangesetOneUpMailRenderer.php',
'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php',
@ -396,6 +398,7 @@ phutil_register_library_map(array(
'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php',
'DifferentialChangesetQuery' => 'applications/differential/query/DifferentialChangesetQuery.php',
'DifferentialChangesetRenderer' => 'applications/differential/render/DifferentialChangesetRenderer.php',
'DifferentialChangesetSearchEngine' => 'applications/differential/query/DifferentialChangesetSearchEngine.php',
'DifferentialChangesetTestRenderer' => 'applications/differential/render/DifferentialChangesetTestRenderer.php',
'DifferentialChangesetTwoUpRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpRenderer.php',
'DifferentialChangesetTwoUpTestRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpTestRenderer.php',
@ -529,6 +532,7 @@ phutil_register_library_map(array(
'DifferentialRevisionAffectedFilesHeraldField' => 'applications/differential/herald/DifferentialRevisionAffectedFilesHeraldField.php',
'DifferentialRevisionAuthorHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorHeraldField.php',
'DifferentialRevisionAuthorProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorProjectsHeraldField.php',
'DifferentialRevisionBuildableTransaction' => 'applications/differential/xaction/DifferentialRevisionBuildableTransaction.php',
'DifferentialRevisionCloseDetailsController' => 'applications/differential/controller/DifferentialRevisionCloseDetailsController.php',
'DifferentialRevisionCloseTransaction' => 'applications/differential/xaction/DifferentialRevisionCloseTransaction.php',
'DifferentialRevisionClosedStatusDatasource' => 'applications/differential/typeahead/DifferentialRevisionClosedStatusDatasource.php',
@ -638,6 +642,7 @@ phutil_register_library_map(array(
'DiffusionBrowseQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php',
'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php',
'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php',
'DiffusionBuildableEngine' => 'applications/diffusion/harbormaster/DiffusionBuildableEngine.php',
'DiffusionCacheEngineExtension' => 'applications/diffusion/engineextension/DiffusionCacheEngineExtension.php',
'DiffusionCachedResolveRefsQuery' => 'applications/diffusion/query/DiffusionCachedResolveRefsQuery.php',
'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php',
@ -657,6 +662,7 @@ phutil_register_library_map(array(
'DiffusionCommitAutocloseHeraldField' => 'applications/diffusion/herald/DiffusionCommitAutocloseHeraldField.php',
'DiffusionCommitBranchesController' => 'applications/diffusion/controller/DiffusionCommitBranchesController.php',
'DiffusionCommitBranchesHeraldField' => 'applications/diffusion/herald/DiffusionCommitBranchesHeraldField.php',
'DiffusionCommitBuildableTransaction' => 'applications/diffusion/xaction/DiffusionCommitBuildableTransaction.php',
'DiffusionCommitCommitterHeraldField' => 'applications/diffusion/herald/DiffusionCommitCommitterHeraldField.php',
'DiffusionCommitCommitterProjectsHeraldField' => 'applications/diffusion/herald/DiffusionCommitCommitterProjectsHeraldField.php',
'DiffusionCommitConcernTransaction' => 'applications/diffusion/xaction/DiffusionCommitConcernTransaction.php',
@ -1285,6 +1291,7 @@ phutil_register_library_map(array(
'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php',
'HarbormasterBuildableActionController' => 'applications/harbormaster/controller/HarbormasterBuildableActionController.php',
'HarbormasterBuildableAdapterInterface' => 'applications/harbormaster/herald/HarbormasterBuildableAdapterInterface.php',
'HarbormasterBuildableEngine' => 'applications/harbormaster/engine/HarbormasterBuildableEngine.php',
'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php',
'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php',
'HarbormasterBuildablePHIDType' => 'applications/harbormaster/phid/HarbormasterBuildablePHIDType.php',
@ -1321,6 +1328,7 @@ phutil_register_library_map(array(
'HarbormasterLogWorker' => 'applications/harbormaster/worker/HarbormasterLogWorker.php',
'HarbormasterManagementArchiveLogsWorkflow' => 'applications/harbormaster/management/HarbormasterManagementArchiveLogsWorkflow.php',
'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php',
'HarbormasterManagementPublishWorkflow' => 'applications/harbormaster/management/HarbormasterManagementPublishWorkflow.php',
'HarbormasterManagementRebuildLogWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRebuildLogWorkflow.php',
'HarbormasterManagementRestartWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php',
'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php',
@ -5586,6 +5594,7 @@ phutil_register_library_map(array(
'DifferentialBlockHeraldAction' => 'HeraldAction',
'DifferentialBlockingReviewerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DifferentialBranchField' => 'DifferentialCustomField',
'DifferentialBuildableEngine' => 'HarbormasterBuildableEngine',
'DifferentialChangeDetailMailView' => 'DifferentialMailView',
'DifferentialChangeHeraldFieldGroup' => 'HeraldFieldGroup',
'DifferentialChangeType' => 'Phobject',
@ -5598,6 +5607,7 @@ phutil_register_library_map(array(
'DifferentialChangesetDetailView' => 'AphrontView',
'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject',
'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer',
'DifferentialChangesetListController' => 'DifferentialController',
'DifferentialChangesetListView' => 'AphrontView',
'DifferentialChangesetOneUpMailRenderer' => 'DifferentialChangesetRenderer',
'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer',
@ -5606,6 +5616,7 @@ phutil_register_library_map(array(
'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase',
'DifferentialChangesetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DifferentialChangesetRenderer' => 'Phobject',
'DifferentialChangesetSearchEngine' => 'PhabricatorApplicationSearchEngine',
'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer',
'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer',
'DifferentialChangesetTwoUpTestRenderer' => 'DifferentialChangesetTestRenderer',
@ -5774,6 +5785,7 @@ phutil_register_library_map(array(
'DifferentialRevisionAffectedFilesHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionAuthorHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionAuthorProjectsHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionBuildableTransaction' => 'DifferentialRevisionTransactionType',
'DifferentialRevisionCloseDetailsController' => 'DifferentialController',
'DifferentialRevisionCloseTransaction' => 'DifferentialRevisionActionTransaction',
'DifferentialRevisionClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource',
@ -5883,6 +5895,7 @@ phutil_register_library_map(array(
'DiffusionBrowseQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionBrowseResultSet' => 'Phobject',
'DiffusionBrowseTableView' => 'DiffusionView',
'DiffusionBuildableEngine' => 'HarbormasterBuildableEngine',
'DiffusionCacheEngineExtension' => 'PhabricatorCacheEngineExtension',
'DiffusionCachedResolveRefsQuery' => 'DiffusionLowLevelQuery',
'DiffusionChangeController' => 'DiffusionController',
@ -5902,6 +5915,7 @@ phutil_register_library_map(array(
'DiffusionCommitAutocloseHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitBranchesController' => 'DiffusionController',
'DiffusionCommitBranchesHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitBuildableTransaction' => 'DiffusionCommitTransactionType',
'DiffusionCommitCommitterHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitCommitterProjectsHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitConcernTransaction' => 'DiffusionCommitAuditTransaction',
@ -6636,6 +6650,7 @@ phutil_register_library_map(array(
'PhabricatorDestructibleInterface',
),
'HarbormasterBuildableActionController' => 'HarbormasterController',
'HarbormasterBuildableEngine' => 'Phobject',
'HarbormasterBuildableListController' => 'HarbormasterController',
'HarbormasterBuildablePHIDType' => 'PhabricatorPHIDType',
'HarbormasterBuildableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@ -6669,6 +6684,7 @@ phutil_register_library_map(array(
'HarbormasterLogWorker' => 'HarbormasterWorker',
'HarbormasterManagementArchiveLogsWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementPublishWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementRebuildLogWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementRestartWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow',

View file

@ -52,7 +52,13 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'DifferentialRevisionListController',
'diff/' => array(
'(?P<id>[1-9]\d*)/' => 'DifferentialDiffViewController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DifferentialDiffViewController',
'changesets/' => array(
$this->getQueryRoutePattern()
=> 'DifferentialChangesetListController',
),
),
'create/' => 'DifferentialDiffCreateController',
),
'changeset/' => 'DifferentialChangesetViewController',

View file

@ -56,10 +56,7 @@ final class DifferentialCreateRawDiffConduitAPIMethod
throw new Exception(
pht(
'The raw diff you have submitted is too large to parse (it affects '.
'more than %s paths and hunks). Differential should only be used '.
'for changes which are small enough to receive detailed human '.
'review. See "Differential User Guide: Large Changes" in the '.
'documentation for more information.',
'more than %s paths and hunks).',
new PhutilNumber($raw_limit)));
}

View file

@ -0,0 +1,51 @@
<?php
final class DifferentialChangesetListController
extends DifferentialController {
private $diff;
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$diff = id(new DifferentialDiffQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
->executeOne();
if (!$diff) {
return new Aphront404Response();
}
$this->diff = $diff;
return id(new DifferentialChangesetSearchEngine())
->setController($this)
->setDiff($diff)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$diff = $this->diff;
if ($diff) {
$revision = $diff->getRevision();
if ($revision) {
$crumbs->addTextCrumb(
$revision->getMonogram(),
$revision->getURI());
}
$crumbs->addTextCrumb(
pht('Diff %d', $diff->getID()),
$diff->getURI());
}
return $crumbs;
}
}

View file

@ -3,11 +3,20 @@
final class DifferentialRevisionViewController extends DifferentialController {
private $revisionID;
private $veryLargeDiff;
public function shouldAllowPublic() {
return true;
}
public function isVeryLargeDiff() {
return $this->veryLargeDiff;
}
public function getVeryLargeDiffLimit() {
return 1000;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$this->revisionID = $request->getURIData('id');
@ -73,6 +82,10 @@ final class DifferentialRevisionViewController extends DifferentialController {
idx($diffs, $diff_vs),
$repository);
if (count($rendering_references) > $this->getVeryLargeDiffLimit()) {
$this->veryLargeDiff = true;
}
if ($request->getExists('download')) {
return $this->buildRawDiffResponse(
$revision,
@ -145,12 +158,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
if (count($changesets) > $limit && !$large) {
$count = count($changesets);
$warning = new PHUIInfoView();
$warning->setTitle(pht('Very Large Diff'));
$warning->setTitle(pht('Large Diff'));
$warning->setSeverity(PHUIInfoView::SEVERITY_WARNING);
$warning->appendChild(hsprintf(
'%s <strong>%s</strong>',
pht(
'This diff is very large and affects %s files. '.
'This diff is large and affects %s files. '.
'You may load each file individually or ',
new PhutilNumber($count)),
phutil_tag(
@ -265,35 +278,53 @@ final class DifferentialRevisionViewController extends DifferentialController {
$timeline->setQuoteRef($revision->getMonogram());
$changeset_view = id(new DifferentialChangesetListView())
->setChangesets($changesets)
->setVisibleChangesets($visible_changesets)
->setStandaloneURI('/differential/changeset/')
->setRawFileURIs(
'/differential/changeset/?view=old',
'/differential/changeset/?view=new')
->setUser($viewer)
->setDiff($target)
->setRenderingReferences($rendering_references)
->setVsMap($vs_map)
->setWhitespace($whitespace)
->setSymbolIndexes($symbol_indexes)
->setTitle(pht('Diff %s', $target->getID()))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
if ($this->isVeryLargeDiff()) {
$messages = array();
$messages[] = pht(
'This very large diff affects more than %s files. Use the %s to '.
'browse changes.',
new PhutilNumber($this->getVeryLargeDiffLimit()),
phutil_tag(
'a',
array(
'href' => '/differential/diff/'.$target->getID().'/changesets/',
),
phutil_tag('strong', array(), pht('Changeset List'))));
$changeset_view = id(new PHUIInfoView())
->setErrors($messages);
} else {
$changeset_view = id(new DifferentialChangesetListView())
->setChangesets($changesets)
->setVisibleChangesets($visible_changesets)
->setStandaloneURI('/differential/changeset/')
->setRawFileURIs(
'/differential/changeset/?view=old',
'/differential/changeset/?view=new')
->setUser($viewer)
->setDiff($target)
->setRenderingReferences($rendering_references)
->setVsMap($vs_map)
->setWhitespace($whitespace)
->setSymbolIndexes($symbol_indexes)
->setTitle(pht('Diff %s', $target->getID()))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
$revision_id = $revision->getID();
$inline_list_uri = "/revision/inlines/{$revision_id}/";
$inline_list_uri = $this->getApplicationURI($inline_list_uri);
$changeset_view->setInlineListURI($inline_list_uri);
$revision_id = $revision->getID();
$inline_list_uri = "/revision/inlines/{$revision_id}/";
$inline_list_uri = $this->getApplicationURI($inline_list_uri);
$changeset_view->setInlineListURI($inline_list_uri);
if ($repository) {
$changeset_view->setRepository($repository);
}
if ($repository) {
$changeset_view->setRepository($repository);
}
if (!$viewer_is_anonymous) {
$changeset_view->setInlineCommentControllerURI(
'/differential/comment/inline/edit/'.$revision->getID().'/');
if (!$viewer_is_anonymous) {
$changeset_view->setInlineCommentControllerURI(
'/differential/comment/inline/edit/'.$revision->getID().'/');
}
}
$broken_diffs = $this->loadHistoryDiffStatus($diffs);
@ -312,7 +343,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
->setLocalCommits(idx($props, 'local:commits'))
->setCommitsForLinks($commits_for_links);
if ($repository) {
if ($repository && !$this->isVeryLargeDiff()) {
$other_revisions = $this->loadOtherRevisions(
$changesets,
$target,
@ -328,10 +359,14 @@ final class DifferentialRevisionViewController extends DifferentialController {
$this->buildPackageMaps($changesets);
$toc_view = $this->buildTableOfContents(
$changesets,
$visible_changesets,
$target->loadCoverageMap($viewer));
if ($this->isVeryLargeDiff()) {
$toc_view = null;
} else {
$toc_view = $this->buildTableOfContents(
$changesets,
$visible_changesets,
$target->loadCoverageMap($viewer));
}
// Attach changesets to each reviewer so we can show which Owners package
// reviewers own no files.
@ -341,12 +376,17 @@ final class DifferentialRevisionViewController extends DifferentialController {
$reviewer->attachChangesets($reviewer_changesets);
}
$tab_group = id(new PHUITabGroupView())
->addTab(
$tab_group = id(new PHUITabGroupView());
if ($toc_view) {
$tab_group->addTab(
id(new PHUITabView())
->setName(pht('Files'))
->setKey('files')
->appendChild($toc_view))
->appendChild($toc_view));
}
$tab_group
->addTab(
id(new PHUITabView())
->setName(pht('History'))
@ -399,8 +439,18 @@ final class DifferentialRevisionViewController extends DifferentialController {
->appendChild($other_view));
}
$view_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Changeset List'))
->setHref('/differential/diff/'.$target->getID().'/changesets/')
->setIcon('fa-align-left');
$tab_header = id(new PHUIHeaderView())
->setHeader(pht('Revision Contents'))
->addActionLink($view_button);
$tab_view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Revision Contents'))
->setHeader($tab_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addTabGroup($tab_group);
@ -469,7 +519,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
PhabricatorShowFiletreeSetting::VALUE_ENABLE_FILETREE);
$nav = null;
if ($filetree_on) {
if ($filetree_on && !$this->isVeryLargeDiff()) {
$collapsed_key = PhabricatorFiletreeVisibleSetting::SETTINGKEY;
$collapsed_value = $viewer->getUserSetting($collapsed_key);
@ -525,11 +575,27 @@ final class DifferentialRevisionViewController extends DifferentialController {
$status_tag = id(new PHUITagView())
->setName($revision->getStatusDisplayName())
->setIcon($revision->getStatusIcon())
->setColor($revision->getStatusIconColor())
->setColor($revision->getStatusTagColor())
->setType(PHUITagView::TYPE_SHADE);
$view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_tag);
// If the revision is in a status other than "Draft", but not broadcasting,
// add an additional "Draft" tag to the header to make it clear that this
// revision hasn't promoted yet.
if (!$revision->getShouldBroadcast() && !$revision->isDraft()) {
$draft_status = DifferentialRevisionStatus::newForStatus(
DifferentialRevisionStatus::DRAFT);
$draft_tag = id(new PHUITagView())
->setName($draft_status->getDisplayName())
->setIcon($draft_status->getIcon())
->setColor($draft_status->getTagColor())
->setType(PHUITagView::TYPE_SHADE);
$view->addTag($draft_tag);
}
return $view;
}
@ -853,17 +919,11 @@ final class DifferentialRevisionViewController extends DifferentialController {
$header = id(new PHUIHeaderView())
->setHeader(pht('Recent Similar Revisions'));
$view = id(new DifferentialRevisionListView())
return id(new DifferentialRevisionListView())
->setViewer($viewer)
->setRevisions($revisions)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setNoBox(true)
->setUser($viewer);
$phids = $view->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$view->setHandles($handles);
return $view;
->setNoBox(true);
}

View file

@ -58,7 +58,7 @@ final class DifferentialDraftField
);
$blocking_map = array_fuse($blocking_map);
$builds = $revision->loadActiveBuilds($viewer);
$builds = $revision->loadImpactfulBuilds($viewer);
$waiting = array();
$blocking = array();
@ -101,7 +101,7 @@ final class DifferentialDraftField
public function getWarningsForDetailView() {
$revision = $this->getObject();
if (!$revision->isDraft()) {
if ($revision->getShouldBroadcast()) {
return array();
}

View file

@ -7,10 +7,10 @@ final class DifferentialTransactionEditor
private $isCloseByCommit;
private $repositoryPHIDOverride = false;
private $didExpandInlineState = false;
private $hasReviewTransaction = false;
private $affectedPaths;
private $firstBroadcast = false;
private $wasDraft = false;
private $wasBroadcasting;
private $isDraftDemotion;
public function getEditorApplicationClass() {
return 'PhabricatorDifferentialApplication';
@ -127,17 +127,15 @@ final class DifferentialTransactionEditor
// built it for us so we don't need to expand it again.
$this->didExpandInlineState = true;
break;
case DifferentialRevisionAcceptTransaction::TRANSACTIONTYPE:
case DifferentialRevisionRejectTransaction::TRANSACTIONTYPE:
case DifferentialRevisionResignTransaction::TRANSACTIONTYPE:
// If we have a review transaction, we'll skip marking the user
// as "Commented" later. This should get cleaner after T10967.
$this->hasReviewTransaction = true;
case DifferentialRevisionPlanChangesTransaction::TRANSACTIONTYPE:
if ($xaction->getMetadataValue('draft.demote')) {
$this->isDraftDemotion = true;
}
break;
}
}
$this->wasDraft = $object->isDraft();
$this->wasBroadcasting = $object->getShouldBroadcast();
return parent::expandTransactions($object, $xactions);
}
@ -487,7 +485,7 @@ final class DifferentialTransactionEditor
PhabricatorLiskDAO $object,
array $xactions) {
if (!$object->shouldBroadcast()) {
if (!$object->getShouldBroadcast()) {
return false;
}
@ -497,27 +495,42 @@ final class DifferentialTransactionEditor
protected function shouldSendMail(
PhabricatorLiskDAO $object,
array $xactions) {
if (!$object->shouldBroadcast()) {
return false;
}
return true;
}
protected function getMailTo(PhabricatorLiskDAO $object) {
$this->requireReviewers($object);
if ($object->getShouldBroadcast()) {
$this->requireReviewers($object);
$phids = array();
$phids[] = $object->getAuthorPHID();
foreach ($object->getReviewers() as $reviewer) {
if ($reviewer->isResigned()) {
continue;
$phids = array();
$phids[] = $object->getAuthorPHID();
foreach ($object->getReviewers() as $reviewer) {
if ($reviewer->isResigned()) {
continue;
}
$phids[] = $reviewer->getReviewerPHID();
}
$phids[] = $reviewer->getReviewerPHID();
return $phids;
}
return $phids;
// If we're demoting a draft after a build failure, just notify the author.
if ($this->isDraftDemotion) {
$author_phid = $object->getAuthorPHID();
return array(
$author_phid,
);
}
return array();
}
protected function getMailCC(PhabricatorLiskDAO $object) {
if (!$object->getShouldBroadcast()) {
return array();
}
return parent::getMailCC($object);
}
protected function newMailUnexpandablePHIDs(PhabricatorLiskDAO $object) {
@ -555,7 +568,7 @@ final class DifferentialTransactionEditor
if ($show_lines) {
$count = new PhutilNumber($object->getLineCount());
$action = pht('%s, %s line(s)', $action, $count);
$action = pht('%s] [%s', $action, $object->getRevisionScaleGlyphs());
}
return $action;
@ -1152,7 +1165,7 @@ final class DifferentialTransactionEditor
// If the object is still a draft, prevent "Send me an email" and other
// similar rules from acting yet.
if (!$object->shouldBroadcast()) {
if (!$object->getShouldBroadcast()) {
$adapter->setForbiddenAction(
HeraldMailableState::STATECONST,
DifferentialHeraldStateReasons::REASON_DRAFT);
@ -1408,12 +1421,14 @@ final class DifferentialTransactionEditor
return array(
'changedPriorToCommitURI' => $this->changedPriorToCommitURI,
'firstBroadcast' => $this->firstBroadcast,
'isDraftDemotion' => $this->isDraftDemotion,
);
}
protected function loadCustomWorkerState(array $state) {
$this->changedPriorToCommitURI = idx($state, 'changedPriorToCommitURI');
$this->firstBroadcast = idx($state, 'firstBroadcast');
$this->isDraftDemotion = idx($state, 'isDraftDemotion');
return $this;
}
@ -1539,8 +1554,12 @@ final class DifferentialTransactionEditor
}
if ($object->isDraft() && $auto_undraft) {
$active_builds = $this->hasActiveBuilds($object);
if (!$active_builds) {
$status = $this->loadCompletedBuildableStatus($object);
$is_passed = ($status === HarbormasterBuildableStatus::STATUS_PASSED);
$is_failed = ($status === HarbormasterBuildableStatus::STATUS_FAILED);
if ($is_passed) {
// When Harbormaster moves a revision out of the draft state, we
// attribute the action to the revision author since this is more
// natural and more useful.
@ -1572,6 +1591,22 @@ final class DifferentialTransactionEditor
// batch of transactions finishes so that Herald can fire on the new
// revision state. See T13027 for discussion.
$this->queueTransaction($xaction);
} else if ($is_failed) {
// When demoting a revision, we act as "Harbormaster" instead of
// the author since this feels a little more natural.
$harbormaster_phid = id(new PhabricatorHarbormasterApplication())
->getPHID();
$xaction = $object->getApplicationTransactionTemplate()
->setAuthorPHID($harbormaster_phid)
->setMetadataValue('draft.demote', true)
->setTransactionType(
DifferentialRevisionPlanChangesTransaction::TRANSACTIONTYPE)
->setNewValue(true);
$this->queueTransaction($xaction);
// TODO: Notify the author (only) that we did this.
}
}
@ -1587,32 +1622,24 @@ final class DifferentialTransactionEditor
// email so the mail gets enriched with "SUMMARY" and "TEST PLAN".
$is_new = $this->getIsNewObject();
$was_draft = $this->wasDraft;
$was_broadcasting = $this->wasBroadcasting;
if (!$object->isDraft() && ($was_draft || $is_new)) {
if (!$object->getHasBroadcast()) {
if ($object->getShouldBroadcast()) {
if (!$was_broadcasting || $is_new) {
// Mark this as the first broadcast we're sending about the revision
// so mail can generate specially.
$this->firstBroadcast = true;
$object
->setHasBroadcast(true)
->save();
}
}
return $xactions;
}
private function hasActiveBuilds($object) {
private function loadCompletedBuildableStatus(
DifferentialRevision $revision) {
$viewer = $this->requireActor();
$builds = $object->loadActiveBuilds($viewer);
if (!$builds) {
return false;
}
return true;
$builds = $revision->loadImpactfulBuilds($viewer);
return $revision->newBuildableStatusForBuilds($builds);
}
private function requireReviewers(DifferentialRevision $revision) {

View file

@ -0,0 +1,57 @@
<?php
final class DifferentialBuildableEngine
extends HarbormasterBuildableEngine {
protected function getPublishableObject() {
$object = $this->getObject();
if ($object instanceof DifferentialDiff) {
return $object->getRevision();
}
return $object;
}
public function publishBuildable(
HarbormasterBuildable $old,
HarbormasterBuildable $new) {
// If we're publishing to a diff that is not actually attached to a
// revision, we have nothing to publish to, so just bail out.
$revision = $this->getPublishableObject();
if (!$revision) {
return;
}
// Don't publish manual buildables.
if ($new->getIsManualBuildable()) {
return;
}
// Don't publish anything if the buildable is still building. Differential
// treats more buildables as "building" than Harbormaster does, but the
// Differential definition is a superset of the Harbormaster definition.
if ($new->isBuilding()) {
return;
}
$viewer = $this->getViewer();
$old_status = $revision->getBuildableStatus($new->getPHID());
$new_status = $revision->newBuildableStatus($viewer, $new->getPHID());
if ($old_status === $new_status) {
return;
}
$buildable_type = DifferentialRevisionBuildableTransaction::TRANSACTIONTYPE;
$xaction = $this->newTransaction()
->setMetadataValue('harbormaster:buildablePHID', $new->getPHID())
->setTransactionType($buildable_type)
->setNewValue($new_status);
$this->applyTransactions(array($xaction));
}
}

View file

@ -41,19 +41,12 @@ final class DifferentialChangesetQuery
}
}
public function newResultObject() {
return new DifferentialChangeset();
}
protected function loadPage() {
$table = new DifferentialChangeset();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
return $this->loadStandardPage($this->newResultObject());
}
protected function willFilterPage(array $changesets) {
@ -124,26 +117,24 @@ final class DifferentialChangesetQuery
return $changesets;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->diffs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'diffID IN (%Ld)',
mpull($this->diffs, 'getID'));
}
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'id IN (%Ld)',
$this->ids);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
return $where;
}
public function getQueryApplicationClass() {

View file

@ -0,0 +1,133 @@
<?php
final class DifferentialChangesetSearchEngine
extends PhabricatorApplicationSearchEngine {
private $diff;
public function setDiff(DifferentialDiff $diff) {
$this->diff = $diff;
return $this;
}
public function getDiff() {
return $this->diff;
}
public function getResultTypeDescription() {
return pht('Differential Changesets');
}
public function getApplicationClassName() {
return 'PhabricatorDifferentialApplication';
}
public function newQuery() {
$query = id(new DifferentialChangesetQuery());
if ($this->diff) {
$query->withDiffs(array($this->diff));
}
return $query;
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
return $query;
}
protected function buildCustomSearchFields() {
return array();
}
protected function getURI($path) {
$diff = $this->getDiff();
if ($diff) {
return '/differential/diff/'.$diff->getID().'/changesets/'.$path;
}
throw new PhutilMethodNotImplementedException();
}
protected function getBuiltinQueryNames() {
$names = array();
$names['all'] = pht('All Changesets');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer = $this->requireViewer();
switch ($query_key) {
case 'all':
return $query->setParameter('order', 'oldest');
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $changesets,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($changesets, 'DifferentialChangeset');
$viewer = $this->requireViewer();
$rows = array();
foreach ($changesets as $changeset) {
$link = phutil_tag(
'a',
array(
'href' => '/differential/changeset/?ref='.$changeset->getID(),
),
$changeset->getDisplayFilename());
$type = $changeset->getChangeType();
$title = DifferentialChangeType::getFullNameForChangeType($type);
$add_lines = $changeset->getAddLines();
if (!$add_lines) {
$add_lines = null;
} else {
$add_lines = '+'.$add_lines;
}
$rem_lines = $changeset->getDelLines();
if (!$rem_lines) {
$rem_lines = null;
} else {
$rem_lines = '-'.$rem_lines;
}
$rows[] = array(
$changeset->newFileTreeIcon(),
$title,
$link,
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
null,
pht('Change'),
pht('Path'),
))
->setColumnClasses(
array(
null,
null,
'pri wide',
));
return id(new PhabricatorApplicationSearchResultView())
->setTable($table);
}
}

View file

@ -148,7 +148,7 @@ final class DifferentialRevisionSearchEngine
$viewer = $this->requireViewer();
$template = id(new DifferentialRevisionListView())
->setUser($viewer)
->setViewer($viewer)
->setNoBox($this->isPanelContext());
$bucket = $this->getResultBucket($query);
@ -176,28 +176,16 @@ final class DifferentialRevisionSearchEngine
}
} else {
$views[] = id(clone $template)
->setRevisions($revisions)
->setHandles(array());
->setRevisions($revisions);
}
if (!$views) {
$views[] = id(new DifferentialRevisionListView())
->setUser($viewer)
->setViewer($viewer)
->setNoDataString(pht('No revisions found.'));
}
$phids = array_mergev(mpull($views, 'getRequiredHandlePHIDs'));
if ($phids) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
} else {
$handles = array();
}
foreach ($views as $view) {
$view->setHandles($handles);
$view->setUnlandedDependencies($unlanded);
}

View file

@ -509,10 +509,6 @@ final class DifferentialDiff
return null;
}
public function getHarbormasterPublishablePHID() {
return $this->getHarbormasterContainerPHID();
}
public function getBuildVariables() {
$results = array();
@ -557,6 +553,10 @@ final class DifferentialDiff
);
}
public function newBuildableEngine() {
return new DifferentialBuildableEngine();
}
/* -( HarbormasterCircleCIBuildableInterface )----------------------------- */

View file

@ -59,9 +59,10 @@ final class DifferentialRevision extends DifferentialDAO
const PROPERTY_CLOSED_FROM_ACCEPTED = 'wasAcceptedBeforeClose';
const PROPERTY_DRAFT_HOLD = 'draft.hold';
const PROPERTY_HAS_BROADCAST = 'draft.broadcast';
const PROPERTY_SHOULD_BROADCAST = 'draft.broadcast';
const PROPERTY_LINES_ADDED = 'lines.added';
const PROPERTY_LINES_REMOVED = 'lines.removed';
const PROPERTY_BUILDABLES = 'buildables';
public static function initializeNewRevision(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
@ -74,8 +75,10 @@ final class DifferentialRevision extends DifferentialDAO
if (PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
$initial_state = DifferentialRevisionStatus::DRAFT;
$should_broadcast = false;
} else {
$initial_state = DifferentialRevisionStatus::NEEDS_REVIEW;
$should_broadcast = true;
}
return id(new DifferentialRevision())
@ -84,7 +87,8 @@ final class DifferentialRevision extends DifferentialDAO
->attachRepository(null)
->attachActiveDiff(null)
->attachReviewers(array())
->setModernRevisionStatus($initial_state);
->setModernRevisionStatus($initial_state)
->setShouldBroadcast($should_broadcast);
}
protected function getConfiguration() {
@ -675,6 +679,10 @@ final class DifferentialRevision extends DifferentialDAO
return $this->getStatusObject()->getIconColor();
}
public function getStatusTagColor() {
return $this->getStatusObject()->getTagColor();
}
public function getStatusObject() {
$status = $this->getStatus();
return DifferentialRevisionStatus::newForStatus($status);
@ -700,14 +708,6 @@ final class DifferentialRevision extends DifferentialDAO
return $this;
}
public function shouldBroadcast() {
if (!$this->isDraft()) {
return true;
}
return false;
}
public function getHoldAsDraft() {
return $this->getProperty(self::PROPERTY_DRAFT_HOLD, false);
}
@ -716,12 +716,14 @@ final class DifferentialRevision extends DifferentialDAO
return $this->setProperty(self::PROPERTY_DRAFT_HOLD, $hold);
}
public function getHasBroadcast() {
return $this->getProperty(self::PROPERTY_HAS_BROADCAST, false);
public function getShouldBroadcast() {
return $this->getProperty(self::PROPERTY_SHOULD_BROADCAST, true);
}
public function setHasBroadcast($has_broadcast) {
return $this->setProperty(self::PROPERTY_HAS_BROADCAST, $has_broadcast);
public function setShouldBroadcast($should_broadcast) {
return $this->setProperty(
self::PROPERTY_SHOULD_BROADCAST,
$should_broadcast);
}
public function setAddedLineCount($count) {
@ -740,7 +742,118 @@ final class DifferentialRevision extends DifferentialDAO
return $this->getProperty(self::PROPERTY_LINES_REMOVED);
}
public function loadActiveBuilds(PhabricatorUser $viewer) {
public function hasLineCounts() {
// This data was not populated on older revisions, so it may not be
// present on all revisions.
return isset($this->properties[self::PROPERTY_LINES_ADDED]);
}
public function getRevisionScaleGlyphs() {
$add = $this->getAddedLineCount();
$rem = $this->getRemovedLineCount();
$all = ($add + $rem);
if (!$all) {
return ' ';
}
$map = array(
20 => 2,
50 => 3,
150 => 4,
375 => 5,
1000 => 6,
2500 => 7,
);
$n = 1;
foreach ($map as $size => $count) {
if ($size <= $all) {
$n = $count;
} else {
break;
}
}
$add_n = (int)ceil(($add / $all) * $n);
$rem_n = (int)ceil(($rem / $all) * $n);
while ($add_n + $rem_n > $n) {
if ($add_n > 1) {
$add_n--;
} else {
$rem_n--;
}
}
return
str_repeat('+', $add_n).
str_repeat('-', $rem_n).
str_repeat(' ', (7 - $n));
}
public function getBuildableStatus($phid) {
$buildables = $this->getProperty(self::PROPERTY_BUILDABLES);
if (!is_array($buildables)) {
$buildables = array();
}
$buildable = idx($buildables, $phid);
if (!is_array($buildable)) {
$buildable = array();
}
return idx($buildable, 'status');
}
public function setBuildableStatus($phid, $status) {
$buildables = $this->getProperty(self::PROPERTY_BUILDABLES);
if (!is_array($buildables)) {
$buildables = array();
}
$buildable = idx($buildables, $phid);
if (!is_array($buildable)) {
$buildable = array();
}
$buildable['status'] = $status;
$buildables[$phid] = $buildable;
return $this->setProperty(self::PROPERTY_BUILDABLES, $buildables);
}
public function newBuildableStatus(PhabricatorUser $viewer, $phid) {
// For Differential, we're ignoring autobuilds (local lint and unit)
// when computing build status. Differential only cares about remote
// builds when making publishing and undrafting decisions.
$builds = $this->loadImpactfulBuildsForBuildablePHIDs(
$viewer,
array($phid));
return $this->newBuildableStatusForBuilds($builds);
}
public function newBuildableStatusForBuilds(array $builds) {
// If we have nothing but passing builds, the buildable passes.
if (!$builds) {
return HarbormasterBuildableStatus::STATUS_PASSED;
}
// If we have any completed, non-passing builds, the buildable fails.
foreach ($builds as $build) {
if ($build->isComplete()) {
return HarbormasterBuildableStatus::STATUS_FAILED;
}
}
// Otherwise, we're still waiting for the build to pass or fail.
return null;
}
public function loadImpactfulBuilds(PhabricatorUser $viewer) {
$diff = $this->getActiveDiff();
// NOTE: We can't use `withContainerPHIDs()` here because the container
@ -754,9 +867,18 @@ final class DifferentialRevision extends DifferentialDAO
return array();
}
return $this->loadImpactfulBuildsForBuildablePHIDs(
$viewer,
mpull($buildables, 'getPHID'));
}
private function loadImpactfulBuildsForBuildablePHIDs(
PhabricatorUser $viewer,
array $phids) {
return id(new HarbormasterBuildQuery())
->setViewer($viewer)
->withBuildablePHIDs(mpull($buildables, 'getPHID'))
->withBuildablePHIDs($phids)
->withAutobuilds(false)
->withBuildStatuses(
array(
@ -788,10 +910,6 @@ final class DifferentialRevision extends DifferentialDAO
return $this->getPHID();
}
public function getHarbormasterPublishablePHID() {
return $this->getPHID();
}
public function getBuildVariables() {
return array();
}
@ -800,6 +918,10 @@ final class DifferentialRevision extends DifferentialDAO
return array();
}
public function newBuildableEngine() {
return new DifferentialBuildableEngine();
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */

View file

@ -6,7 +6,6 @@
final class DifferentialRevisionListView extends AphrontView {
private $revisions = array();
private $handles;
private $header;
private $noDataString;
private $noBox;
@ -48,32 +47,43 @@ final class DifferentialRevisionListView extends AphrontView {
return $this;
}
public function getRequiredHandlePHIDs() {
$phids = array();
foreach ($this->revisions as $revision) {
$phids[] = array($revision->getAuthorPHID());
$phids[] = $revision->getReviewerPHIDs();
}
return array_mergev($phids);
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
public function render() {
$viewer = $this->getViewer();
$this->initBehavior('phabricator-tooltips', array());
$this->requireResource('aphront-tooltip-css');
$list = new PHUIObjectItemListView();
$reviewer_limit = 7;
foreach ($this->revisions as $revision) {
$reviewer_phids = array();
$reviewer_more = array();
$handle_phids = array();
foreach ($this->revisions as $key => $revision) {
$reviewers = $revision->getReviewers();
if (count($reviewers) > $reviewer_limit) {
$reviewers = array_slice($reviewers, 0, $reviewer_limit);
$reviewer_more[$key] = true;
} else {
$reviewer_more[$key] = false;
}
$phids = mpull($reviewers, 'getReviewerPHID');
$reviewer_phids[$key] = $phids;
foreach ($phids as $phid) {
$handle_phids[$phid] = $phid;
}
$author_phid = $revision->getAuthorPHID();
$handle_phids[$author_phid] = $author_phid;
}
$handles = $viewer->loadHandles($handle_phids);
$list = new PHUIObjectItemListView();
foreach ($this->revisions as $key => $revision) {
$item = id(new PHUIObjectItemView())
->setUser($viewer);
->setViewer($viewer);
$icons = array();
@ -89,21 +99,22 @@ final class DifferentialRevisionListView extends AphrontView {
'');
}
if ($revision->getHasDraft($viewer)) {
$icons['draft'] = true;
}
$modified = $revision->getDateModified();
if (isset($icons['flag'])) {
$item->addHeadIcon($icons['flag']);
}
$item->setObjectName('D'.$revision->getID());
$item->setObjectName($revision->getMonogram());
$item->setHeader($revision->getTitle());
$item->setHref('/D'.$revision->getID());
$item->setHref($revision->getURI());
if (isset($icons['draft'])) {
$size = $this->renderRevisionSize($revision);
if ($size !== null) {
$item->addAttribute($size);
}
if ($revision->getHasDraft($viewer)) {
$draft = id(new PHUIIconView())
->setIcon('fa-comment yellow')
->addSigil('has-tooltip')
@ -114,8 +125,7 @@ final class DifferentialRevisionListView extends AphrontView {
$item->addAttribute($draft);
}
// Author
$author_handle = $this->handles[$revision->getAuthorPHID()];
$author_handle = $handles[$revision->getAuthorPHID()];
$item->addByline(pht('Author: %s', $author_handle->renderLink()));
$unlanded = idx($this->unlandedDependencies, $phid);
@ -128,17 +138,26 @@ final class DifferentialRevisionListView extends AphrontView {
));
}
$reviewers = array();
foreach ($revision->getReviewerPHIDs() as $reviewer) {
$reviewers[] = $this->handles[$reviewer]->renderLink();
}
if (!$reviewers) {
$reviewers = phutil_tag('em', array(), pht('None'));
$more = null;
if ($reviewer_more[$key]) {
$more = pht(', ...');
} else {
$reviewers = phutil_implode_html(', ', $reviewers);
$more = null;
}
if ($reviewer_phids[$key]) {
$item->addAttribute(
array(
pht('Reviewers:'),
' ',
$viewer->renderHandleList($reviewer_phids[$key])
->setAsInline(true),
$more,
));
} else {
$item->addAttribute(phutil_tag('em', array(), pht('No Reviewers')));
}
$item->addAttribute(pht('Reviewers: %s', $reviewers));
$item->setEpoch($revision->getDateModified());
if ($revision->isClosed()) {
@ -176,4 +195,59 @@ final class DifferentialRevisionListView extends AphrontView {
return $list;
}
private function renderRevisionSize(DifferentialRevision $revision) {
if (!$revision->hasLineCounts()) {
return null;
}
$size = array();
$glyphs = $revision->getRevisionScaleGlyphs();
$plus_count = 0;
for ($ii = 0; $ii < 7; $ii++) {
$c = $glyphs[$ii];
switch ($c) {
case '+':
$size[] = id(new PHUIIconView())
->setIcon('fa-plus');
$plus_count++;
break;
case '-':
$size[] = id(new PHUIIconView())
->setIcon('fa-minus');
break;
default:
$size[] = id(new PHUIIconView())
->setIcon('fa-square-o invisible');
break;
}
}
$n = $revision->getAddedLineCount() + $revision->getRemovedLineCount();
$classes = array();
$classes[] = 'differential-revision-size';
if ($plus_count <= 1) {
$classes[] = 'differential-revision-small';
}
if ($plus_count >= 4) {
$classes[] = 'differential-revision-large';
}
return javelin_tag(
'span',
array(
'class' => implode(' ', $classes),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => pht('%s Lines', new PhutilNumber($n)),
'align' => 'E',
),
),
$size);
}
}

View file

@ -147,10 +147,23 @@ abstract class DifferentialRevisionActionTransaction
$actor = $this->getActor();
$action_exception = null;
try {
$this->validateAction($object, $actor);
} catch (Exception $ex) {
$action_exception = $ex;
foreach ($xactions as $xaction) {
// If this is a draft demotion action, let it skip all the normal
// validation. This is a little hacky and should perhaps move down
// into the actual action implementations, but currently we can not
// apply this rule in validateAction() because it doesn't operate on
// the actual transaction.
if ($xaction->getMetadataValue('draft.demote')) {
continue;
}
try {
$this->validateAction($object, $actor);
} catch (Exception $ex) {
$action_exception = $ex;
}
break;
}
foreach ($xactions as $xaction) {

View file

@ -0,0 +1,93 @@
<?php
final class DifferentialRevisionBuildableTransaction
extends DifferentialRevisionTransactionType {
// NOTE: This uses an older constant for compatibility. We should perhaps
// migrate these at some point.
const TRANSACTIONTYPE = 'harbormaster:buildable';
public function generateNewValue($object, $value) {
return $value;
}
public function generateOldValue($object) {
return $object->getBuildableStatus($this->getBuildablePHID());
}
public function applyInternalEffects($object, $value) {
$object->setBuildableStatus($this->getBuildablePHID(), $value);
}
public function getIcon() {
return $this->newBuildableStatus()->getIcon();
}
public function getColor() {
return $this->newBuildableStatus()->getColor();
}
public function getActionName() {
return $this->newBuildableStatus()->getActionName();
}
public function shouldHideForFeed() {
return !$this->newBuildableStatus()->isFailed();
}
public function shouldHideForMail() {
return !$this->newBuildableStatus()->isFailed();
}
public function getTitle() {
$new = $this->getNewValue();
$buildable_phid = $this->getBuildablePHID();
switch ($new) {
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht(
'%s completed remote builds in %s.',
$this->renderAuthor(),
$this->renderHandle($buildable_phid));
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht(
'%s failed remote builds in %s!',
$this->renderAuthor(),
$this->renderHandle($buildable_phid));
}
return null;
}
public function getTitleForFeed() {
$new = $this->getNewValue();
$buildable_phid = $this->getBuildablePHID();
switch ($new) {
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht(
'%s completed remote builds in %s for %s.',
$this->renderAuthor(),
$this->renderHandle($buildable_phid),
$this->renderObject());
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht(
'%s failed remote builds in %s for %s!',
$this->renderAuthor(),
$this->renderHandle($buildable_phid),
$this->renderObject());
}
return null;
}
private function newBuildableStatus() {
$new = $this->getNewValue();
return HarbormasterBuildableStatus::newBuildableStatusObject($new);
}
private function getBuildablePHID() {
return $this->getMetadataValue('harbormaster:buildablePHID');
}
}

View file

@ -96,9 +96,16 @@ final class DifferentialRevisionPlanChangesTransaction
}
public function getTitle() {
return pht(
'%s planned changes to this revision.',
$this->renderAuthor());
if ($this->isDraftDemotion()) {
return pht(
'%s returned this revision to the author for changes because remote '.
'builds failed.',
$this->renderAuthor());
} else {
return pht(
'%s planned changes to this revision.',
$this->renderAuthor());
}
}
public function getTitleForFeed() {
@ -108,4 +115,8 @@ final class DifferentialRevisionPlanChangesTransaction
$this->renderObject());
}
private function isDraftDemotion() {
return (bool)$this->getMetadataValue('draft.demote');
}
}

View file

@ -48,8 +48,12 @@ final class DifferentialRevisionReclaimTransaction
}
public function applyInternalEffects($object, $value) {
$status_review = DifferentialRevisionStatus::NEEDS_REVIEW;
$object->setModernRevisionStatus($status_review);
if ($object->getShouldBroadcast()) {
$new_status = DifferentialRevisionStatus::NEEDS_REVIEW;
} else {
$new_status = DifferentialRevisionStatus::DRAFT;
}
$object->setModernRevisionStatus($new_status);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -37,7 +37,9 @@ final class DifferentialRevisionRequestReviewTransaction
public function applyInternalEffects($object, $value) {
$status_review = DifferentialRevisionStatus::NEEDS_REVIEW;
$object->setModernRevisionStatus($status_review);
$object
->setModernRevisionStatus($status_review)
->setShouldBroadcast(true);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -13,8 +13,14 @@ final class DifferentialRevisionUpdateTransaction
public function applyInternalEffects($object, $value) {
$should_review = $this->shouldRequestReviewAfterUpdate($object);
if ($should_review) {
$object->setModernRevisionStatus(
DifferentialRevisionStatus::NEEDS_REVIEW);
// If we're updating a non-broadcasting revision, put it back in draft
// rather than moving it directly to "Needs Review".
if ($object->getShouldBroadcast()) {
$new_status = DifferentialRevisionStatus::NEEDS_REVIEW;
} else {
$new_status = DifferentialRevisionStatus::DRAFT;
}
$object->setModernRevisionStatus($new_status);
}
$editor = $this->getEditor();

View file

@ -1754,14 +1754,10 @@ final class DiffusionBrowseController extends DiffusionController {
->setHeader(pht('Recently Open Revisions'));
$list = id(new DifferentialRevisionListView())
->setViewer($viewer)
->setRevisions($revisions)
->setUser($viewer)
->setNoBox(true);
$phids = $list->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
$list->setHandles($handles);
$view = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)

View file

@ -0,0 +1,37 @@
<?php
final class DiffusionBuildableEngine
extends HarbormasterBuildableEngine {
public function publishBuildable(
HarbormasterBuildable $old,
HarbormasterBuildable $new) {
// Don't publish manual buildables.
if ($new->getIsManualBuildable()) {
return;
}
// Don't publish anything if the buildable status has not changed. At
// least for now, Diffusion handles buildable status exactly the same
// way that Harbormaster does.
$old_status = $old->getBuildableStatus();
$new_status = $new->getBuildableStatus();
if ($old_status === $new_status) {
return;
}
// Don't publish anything if the buildable is still building.
if ($new->isBuilding()) {
return;
}
$xaction = $this->newTransaction()
->setMetadataValue('harbormaster:buildablePHID', $new->getPHID())
->setTransactionType(DiffusionCommitBuildableTransaction::TRANSACTIONTYPE)
->setNewValue($new->getBuildableStatus());
$this->applyTransactions(array($xaction));
}
}

View file

@ -0,0 +1,89 @@
<?php
final class DiffusionCommitBuildableTransaction
extends DiffusionCommitTransactionType {
// NOTE: This uses an older constant for compatibility. We should perhaps
// migrate these at some point.
const TRANSACTIONTYPE = 'harbormaster:buildable';
public function generateNewValue($object, $value) {
return $value;
}
public function generateOldValue($object) {
return null;
}
public function getIcon() {
return $this->newBuildableStatus()->getIcon();
}
public function getColor() {
return $this->newBuildableStatus()->getColor();
}
public function getActionName() {
return $this->newBuildableStatus()->getActionName();
}
public function shouldHideForFeed() {
return !$this->newBuildableStatus()->isFailed();
}
public function shouldHideForMail() {
return !$this->newBuildableStatus()->isFailed();
}
public function getTitle() {
$new = $this->getNewValue();
$buildable_phid = $this->getBuildablePHID();
switch ($new) {
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht(
'%s completed building %s.',
$this->renderAuthor(),
$this->renderHandle($buildable_phid));
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht(
'%s failed to build %s!',
$this->renderAuthor(),
$this->renderHandle($buildable_phid));
}
return null;
}
public function getTitleForFeed() {
$new = $this->getNewValue();
$buildable_phid = $this->getBuildablePHID();
switch ($new) {
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht(
'%s completed building %s for %s.',
$this->renderAuthor(),
$this->renderHandle($buildable_phid),
$this->renderObject());
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht(
'%s failed to build %s for %s!',
$this->renderAuthor(),
$this->renderHandle($buildable_phid),
$this->renderObject());
}
return null;
}
private function newBuildableStatus() {
$new = $this->getNewValue();
return HarbormasterBuildableStatus::newBuildableStatusObject($new);
}
private function getBuildablePHID() {
return $this->getMetadataValue('harbormaster:buildablePHID');
}
}

View file

@ -39,6 +39,10 @@ final class HarbormasterBuildableStatus extends Phobject {
return $this->getProperty('name');
}
public function getActionName() {
return $this->getProperty('name.action');
}
public function getColor() {
return $this->getProperty('color');
}
@ -47,6 +51,14 @@ final class HarbormasterBuildableStatus extends Phobject {
return ($this->key === self::STATUS_PREPARING);
}
public function isBuilding() {
return ($this->key === self::STATUS_BUILDING);
}
public function isFailed() {
return ($this->key === self::STATUS_FAILED);
}
public static function getOptionMap() {
return ipull(self::getSpecifications(), 'name');
}
@ -57,21 +69,25 @@ final class HarbormasterBuildableStatus extends Phobject {
'name' => pht('Preparing'),
'color' => 'blue',
'icon' => 'fa-hourglass-o',
'name.action' => pht('Build Preparing'),
),
self::STATUS_BUILDING => array(
'name' => pht('Building'),
'color' => 'blue',
'icon' => 'fa-chevron-circle-right',
'name.action' => pht('Build Started'),
),
self::STATUS_PASSED => array(
'name' => pht('Passed'),
'color' => 'green',
'icon' => 'fa-check-circle',
'name.action' => pht('Build Passed'),
),
self::STATUS_FAILED => array(
'name' => pht('Failed'),
'color' => 'red',
'icon' => 'fa-times-circle',
'name.action' => pht('Build Failed'),
),
);
}
@ -86,6 +102,7 @@ final class HarbormasterBuildableStatus extends Phobject {
'name' => pht('Unknown ("%s")', $status),
'icon' => 'fa-question-circle',
'color' => 'bluegrey',
'name.action' => pht('Build Status'),
);
}

View file

@ -489,6 +489,8 @@ final class HarbormasterBuildEngine extends Phobject {
}
}
$old = clone $buildable;
// Don't update the buildable status if we're still preparing builds: more
// builds may still be scheduled shortly, so even if every build we know
// about so far has passed, that doesn't mean the buildable has actually
@ -515,8 +517,7 @@ final class HarbormasterBuildEngine extends Phobject {
$new_status = HarbormasterBuildableStatus::STATUS_BUILDING;
}
$old_status = $buildable->getBuildableStatus();
$did_update = ($old_status != $new_status);
$did_update = ($old->getBuildableStatus() !== $new_status);
if ($did_update) {
$buildable->setBuildableStatus($new_status);
$buildable->save();
@ -530,81 +531,45 @@ final class HarbormasterBuildEngine extends Phobject {
return;
}
// If we changed the buildable status, try to post a transaction to the
// object about it. We can safely do this outside of the locked region.
$this->publishBuildable($old, $buildable);
}
// NOTE: We only post transactions for automatic buildables, not for
// manual ones: manual builds are test builds, whoever is doing tests
// can look at the results themselves, and other users generally don't
// care about the outcome.
public function publishBuildable(
HarbormasterBuildable $old,
HarbormasterBuildable $new) {
$should_publish =
($did_update) &&
($new_status != HarbormasterBuildableStatus::STATUS_BUILDING) &&
(!$buildable->getIsManualBuildable());
$viewer = $this->getViewer();
if (!$should_publish) {
return;
}
// Publish the buildable. We publish buildables even if they haven't
// changed status in Harbormaster because applications may care about
// different things than Harbormaster does. For example, Differential
// does not care about local lint and unit tests when deciding whether
// a revision should move out of draft or not.
// NOTE: We're publishing both automatic and manual buildables. Buildable
// objects should generally ignore manual buildables, but it's up to them
// to decide.
$object = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($buildable->getBuildablePHID()))
->withPHIDs(array($new->getBuildablePHID()))
->executeOne();
if (!$object) {
return;
}
$publish_phid = $object->getHarbormasterPublishablePHID();
if (!$publish_phid) {
return;
}
if ($publish_phid === $object->getPHID()) {
$publish = $object;
} else {
$publish = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($publish_phid))
->executeOne();
if (!$publish) {
return;
}
}
if (!($publish instanceof PhabricatorApplicationTransactionInterface)) {
return;
}
$template = $publish->getApplicationTransactionTemplate();
if (!$template) {
return;
}
$template
->setTransactionType(PhabricatorTransactions::TYPE_BUILDABLE)
->setMetadataValue(
'harbormaster:buildablePHID',
$buildable->getPHID())
->setOldValue($old_status)
->setNewValue($new_status);
$harbormaster_phid = id(new PhabricatorHarbormasterApplication())
->getPHID();
$engine = HarbormasterBuildableEngine::newForObject($object, $viewer);
$daemon_source = PhabricatorContentSource::newForSource(
PhabricatorDaemonContentSource::SOURCECONST);
$editor = $publish->getApplicationTransactionEditor()
->setActor($viewer)
$harbormaster_phid = id(new PhabricatorHarbormasterApplication())
->getPHID();
$engine
->setActingAsPHID($harbormaster_phid)
->setContentSource($daemon_source)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions(
$publish->getApplicationTransactionObject(),
array($template));
->publishBuildable($old, $new);
}
private function releaseAllArtifacts(HarbormasterBuild $build) {

View file

@ -0,0 +1,105 @@
<?php
abstract class HarbormasterBuildableEngine
extends Phobject {
private $viewer;
private $actingAsPHID;
private $contentSource;
private $object;
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
final public function getViewer() {
return $this->viewer;
}
final public function setActingAsPHID($acting_as_phid) {
$this->actingAsPHID = $acting_as_phid;
return $this;
}
final public function getActingAsPHID() {
return $this->actingAsPHID;
}
final public function setContentSource(
PhabricatorContentSource $content_source) {
$this->contentSource = $content_source;
return $this;
}
final public function getContentSource() {
return $this->contentSource;
}
final public function setObject(HarbormasterBuildableInterface $object) {
$this->object = $object;
return $this;
}
final public function getObject() {
return $this->object;
}
protected function getPublishableObject() {
return $this->getObject();
}
public function publishBuildable(
HarbormasterBuildable $old,
HarbormasterBuildable $new) {
return;
}
final public static function newForObject(
HarbormasterBuildableInterface $object,
PhabricatorUser $viewer) {
return $object->newBuildableEngine()
->setViewer($viewer)
->setObject($object);
}
final protected function newEditor() {
$publishable = $this->getPublishableObject();
$viewer = $this->getViewer();
$editor = $publishable->getApplicationTransactionEditor()
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$acting_as_phid = $this->getActingAsPHID();
if ($acting_as_phid !== null) {
$editor->setActingAsPHID($acting_as_phid);
}
$content_source = $this->getContentSource();
if ($content_source !== null) {
$editor->setContentSource($content_source);
}
return $editor;
}
final protected function newTransaction() {
$publishable = $this->getPublishableObject();
return $publishable->getApplicationTransactionTemplate();
}
final protected function applyTransactions(array $xactions) {
$publishable = $this->getPublishableObject();
$editor = $this->newEditor();
$editor->applyTransactions(
$publishable->getApplicationTransactionObject(),
$xactions);
}
}

View file

@ -18,22 +18,9 @@ interface HarbormasterBuildableInterface {
public function getHarbormasterBuildablePHID();
public function getHarbormasterContainerPHID();
/**
* Get the object PHID which build status should be published to.
*
* In some cases (like commits), this is the object itself. In other cases,
* it is a different object: for example, diffs publish builds to revisions.
*
* This method can return `null` to disable publishing.
*
* @return phid|null Build status updates will be published to this object's
* transaction timeline.
*/
public function getHarbormasterPublishablePHID();
public function getBuildVariables();
public function getAvailableBuildVariables();
public function newBuildableEngine();
}

View file

@ -0,0 +1,87 @@
<?php
final class HarbormasterManagementPublishWorkflow
extends HarbormasterManagementWorkflow {
protected function didConstruct() {
$this
->setName('publish')
->setExamples(pht('**publish** __buildable__ ...'))
->setSynopsis(
pht(
'Publish a buildable. This is primarily useful for developing '.
'and debugging applications which have buildable objects.'))
->setArguments(
array(
array(
'name' => 'buildable',
'wildcard' => true,
),
));
}
public function execute(PhutilArgumentParser $args) {
$viewer = $this->getViewer();
$buildable_names = $args->getArg('buildable');
if (!$buildable_names) {
throw new PhutilArgumentUsageException(
pht(
'Name one or more buildables to publish, like "B123".'));
}
$query = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withNames($buildable_names);
$query->execute();
$result_map = $query->getNamedResults();
foreach ($buildable_names as $name) {
if (!isset($result_map[$name])) {
throw new PhutilArgumentUsageException(
pht(
'Argument "%s" does not name a buildable. Provide one or more '.
'valid buildable monograms or PHIDs.',
$name));
}
}
foreach ($result_map as $name => $result) {
if (!($result instanceof HarbormasterBuildable)) {
throw new PhutilArgumentUsageException(
pht(
'Object "%s" is not a HarbormasterBuildable (it is a "%s"). '.
'Name one or more buildables to publish, like "B123".',
get_class($result)));
}
}
foreach ($result_map as $buildable) {
echo tsprintf(
"%s\n",
pht(
'Publishing "%s"...',
$buildable->getMonogram()));
// Reload the buildable to pick up builds.
$buildable = id(new HarbormasterBuildableQuery())
->setViewer($viewer)
->withIDs(array($buildable->getID()))
->needBuilds(true)
->executeOne();
$engine = id(new HarbormasterBuildEngine())
->setViewer($viewer)
->publishBuildable($buildable, $buildable);
}
echo tsprintf(
"%s\n",
pht('Done.'));
return 0;
}
}

View file

@ -233,6 +233,10 @@ final class HarbormasterBuildable
return $this->getBuildableStatusObject()->isPreparing();
}
public function isBuilding() {
return $this->getBuildableStatusObject()->isBuilding();
}
/* -( Messages )----------------------------------------------------------- */
@ -329,10 +333,6 @@ final class HarbormasterBuildable
return $this->getContainerPHID();
}
public function getHarbormasterPublishablePHID() {
return $this->getBuildableObject()->getHarbormasterPublishablePHID();
}
public function getBuildVariables() {
return array();
}
@ -341,6 +341,10 @@ final class HarbormasterBuildable
return array();
}
public function newBuildableEngine() {
return $this->getBuildableObject()->newBuildableEngine();
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */

View file

@ -63,15 +63,11 @@ final class PhabricatorPeopleProfileRevisionsController
->execute();
$list = id(new DifferentialRevisionListView())
->setUser($viewer)
->setViewer($viewer)
->setNoBox(true)
->setRevisions($revisions)
->setNoDataString(pht('No recent revisions.'));
$object_phids = $list->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($object_phids);
$list->setHandles($handles);
$view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Recent Revisions'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)

View file

@ -517,10 +517,6 @@ final class PhabricatorRepositoryCommit
return $this->getRepository()->getPHID();
}
public function getHarbormasterPublishablePHID() {
return $this->getPHID();
}
public function getBuildVariables() {
$results = array();
@ -549,6 +545,10 @@ final class PhabricatorRepositoryCommit
);
}
public function newBuildableEngine() {
return new DiffusionBuildableEngine();
}
/* -( HarbormasterCircleCIBuildableInterface )----------------------------- */

View file

@ -9,7 +9,6 @@ final class PhabricatorTransactions extends Phobject {
const TYPE_JOIN_POLICY = 'core:join-policy';
const TYPE_EDGE = 'core:edge';
const TYPE_CUSTOMFIELD = 'core:customfield';
const TYPE_BUILDABLE = 'harbormaster:buildable';
const TYPE_TOKEN = 'token:give';
const TYPE_INLINESTATE = 'core:inlinestate';
const TYPE_SPACE = 'core:space';

View file

@ -313,10 +313,6 @@ abstract class PhabricatorApplicationTransactionEditor
$types[] = PhabricatorTransactions::TYPE_CUSTOMFIELD;
}
if ($this->object instanceof HarbormasterBuildableInterface) {
$types[] = PhabricatorTransactions::TYPE_BUILDABLE;
}
if ($this->object instanceof PhabricatorTokenReceiverInterface) {
$types[] = PhabricatorTransactions::TYPE_TOKEN;
}
@ -469,7 +465,6 @@ abstract class PhabricatorApplicationTransactionEditor
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:
case PhabricatorTransactions::TYPE_JOIN_POLICY:
case PhabricatorTransactions::TYPE_BUILDABLE:
case PhabricatorTransactions::TYPE_TOKEN:
case PhabricatorTransactions::TYPE_INLINESTATE:
case PhabricatorTransactions::TYPE_SUBTYPE:
@ -610,7 +605,6 @@ abstract class PhabricatorApplicationTransactionEditor
return $field->applyApplicationTransactionInternalEffects($xaction);
case PhabricatorTransactions::TYPE_CREATE:
case PhabricatorTransactions::TYPE_SUBTYPE:
case PhabricatorTransactions::TYPE_BUILDABLE:
case PhabricatorTransactions::TYPE_TOKEN:
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:
@ -673,7 +667,6 @@ abstract class PhabricatorApplicationTransactionEditor
case PhabricatorTransactions::TYPE_CREATE:
case PhabricatorTransactions::TYPE_SUBTYPE:
case PhabricatorTransactions::TYPE_EDGE:
case PhabricatorTransactions::TYPE_BUILDABLE:
case PhabricatorTransactions::TYPE_TOKEN:
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:

View file

@ -54,7 +54,6 @@ abstract class PhabricatorApplicationTransaction
public function shouldGenerateOldValue() {
switch ($this->getTransactionType()) {
case PhabricatorTransactions::TYPE_BUILDABLE:
case PhabricatorTransactions::TYPE_TOKEN:
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
case PhabricatorTransactions::TYPE_INLINESTATE:
@ -339,12 +338,6 @@ abstract class PhabricatorApplicationTransaction
break;
case PhabricatorTransactions::TYPE_TOKEN:
break;
case PhabricatorTransactions::TYPE_BUILDABLE:
$phid = $this->getMetadataValue('harbormaster:buildablePHID');
if ($phid) {
$phids[] = array($phid);
}
break;
}
if ($this->getComment()) {
@ -470,8 +463,6 @@ abstract class PhabricatorApplicationTransaction
return 'fa-ambulance';
}
return 'fa-link';
case PhabricatorTransactions::TYPE_BUILDABLE:
return 'fa-wrench';
case PhabricatorTransactions::TYPE_TOKEN:
return 'fa-trophy';
case PhabricatorTransactions::TYPE_SPACE:
@ -515,14 +506,6 @@ abstract class PhabricatorApplicationTransaction
return 'sky';
}
break;
case PhabricatorTransactions::TYPE_BUILDABLE:
switch ($this->getNewValue()) {
case HarbormasterBuildableStatus::STATUS_PASSED:
return 'green';
case HarbormasterBuildableStatus::STATUS_FAILED:
return 'red';
}
break;
}
return null;
}
@ -679,15 +662,6 @@ abstract class PhabricatorApplicationTransaction
switch ($this->getTransactionType()) {
case PhabricatorTransactions::TYPE_TOKEN:
return true;
case PhabricatorTransactions::TYPE_BUILDABLE:
switch ($this->getNewValue()) {
case HarbormasterBuildableStatus::STATUS_FAILED:
// For now, only ever send mail when builds fail. We might let
// you customize this later, but in most cases this is probably
// completely uninteresting.
return false;
}
return true;
case PhabricatorTransactions::TYPE_EDGE:
$edge_type = $this->getMetadataValue('edge:type');
switch ($edge_type) {
@ -742,16 +716,6 @@ abstract class PhabricatorApplicationTransaction
switch ($this->getTransactionType()) {
case PhabricatorTransactions::TYPE_TOKEN:
return true;
case PhabricatorTransactions::TYPE_BUILDABLE:
switch ($this->getNewValue()) {
case HarbormasterBuildableStatus::STATUS_FAILED:
// For now, don't notify on build passes either. These are pretty
// high volume and annoying, with very little present value. We
// might want to turn them back on in the specific case of
// build successes on the current document?
return false;
}
return true;
case PhabricatorTransactions::TYPE_EDGE:
$edge_type = $this->getMetadataValue('edge:type');
switch ($edge_type) {
@ -1027,30 +991,6 @@ abstract class PhabricatorApplicationTransaction
$this->renderHandleLink($author_phid));
}
case PhabricatorTransactions::TYPE_BUILDABLE:
switch ($this->getNewValue()) {
case HarbormasterBuildableStatus::STATUS_BUILDING:
return pht(
'%s started building %s.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink(
$this->getMetadataValue('harbormaster:buildablePHID')));
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht(
'%s completed building %s.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink(
$this->getMetadataValue('harbormaster:buildablePHID')));
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht(
'%s failed to build %s!',
$this->renderHandleLink($author_phid),
$this->renderHandleLink(
$this->getMetadataValue('harbormaster:buildablePHID')));
default:
return null;
}
case PhabricatorTransactions::TYPE_INLINESTATE:
$done = 0;
$undone = 0;
@ -1239,32 +1179,6 @@ abstract class PhabricatorApplicationTransaction
$this->renderHandleLink($author_phid),
$this->renderHandleLink($object_phid));
}
case PhabricatorTransactions::TYPE_BUILDABLE:
switch ($this->getNewValue()) {
case HarbormasterBuildableStatus::STATUS_BUILDING:
return pht(
'%s started building %s for %s.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink(
$this->getMetadataValue('harbormaster:buildablePHID')),
$this->renderHandleLink($object_phid));
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht(
'%s completed building %s for %s.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink(
$this->getMetadataValue('harbormaster:buildablePHID')),
$this->renderHandleLink($object_phid));
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht(
'%s failed to build %s for %s.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink(
$this->getMetadataValue('harbormaster:buildablePHID')),
$this->renderHandleLink($object_phid));
default:
return null;
}
case PhabricatorTransactions::TYPE_COLUMNS:
$moves = $this->getInterestingMoves($new);
@ -1421,15 +1335,6 @@ abstract class PhabricatorApplicationTransaction
return pht('Changed Policy');
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
return pht('Changed Subscribers');
case PhabricatorTransactions::TYPE_BUILDABLE:
switch ($this->getNewValue()) {
case HarbormasterBuildableStatus::STATUS_PASSED:
return pht('Build Passed');
case HarbormasterBuildableStatus::STATUS_FAILED:
return pht('Build Failed');
default:
return pht('Build Status');
}
default:
return pht('Updated');
}

View file

@ -100,6 +100,14 @@ abstract class PhabricatorModularTransaction
return parent::shouldHideForFeed();
}
/* final */ public function shouldHideForMail(array $xactions) {
if ($this->getTransactionImplementation()->shouldHideForMail()) {
return true;
}
return parent::shouldHideForMail($xactions);
}
/* final */ public function getIcon() {
$icon = $this->getTransactionImplementation()->getIcon();
if ($icon !== null) {
@ -168,7 +176,7 @@ abstract class PhabricatorModularTransaction
return parent::attachViewer($viewer);
}
/* final */ public function hasChangeDetails() {
final public function hasChangeDetails() {
if ($this->getTransactionImplementation()->hasChangeDetailView()) {
return true;
}
@ -176,7 +184,7 @@ abstract class PhabricatorModularTransaction
return parent::hasChangeDetails();
}
/* final */ public function renderChangeDetails(PhabricatorUser $viewer) {
final public function renderChangeDetails(PhabricatorUser $viewer) {
$impl = $this->getTransactionImplementation();
$impl->setViewer($viewer);
$view = $impl->newChangeDetailView();

View file

@ -51,6 +51,10 @@ abstract class PhabricatorModularTransactionType
return false;
}
public function shouldHideForMail() {
return false;
}
public function getIcon() {
return null;
}

View file

@ -74,9 +74,6 @@ often well-correlated with complexity.
We generally follow these practices in Phabricator. The median change size for
Phabricator is 35 lines.
See @{article:Differential User Guide: Large Changes} for information about
reviewing big checkins.
= Write Sensible Commit Messages =
There are lots of resources for this on the internet. All of them say pretty

View file

@ -66,8 +66,6 @@ Continue by:
- diving into the details of inline comments in
@{article:Differential User Guide: Inline Comments}; or
- reading the FAQ at @{article:Differential User Guide: FAQ}; or
- learning about handling large changesets in
@{article:Differential User Guide: Large Changes}; or
- learning about test plans in
@{article:Differential User Guide: Test Plans}; or
- learning more about Herald in @{article:Herald User Guide}.

View file

@ -1,54 +0,0 @@
@title Differential User Guide: Large Changes
@group userguide
Dealing with huge changesets, and when **not** to use Differential.
= Overview =
When you want code review for a given changeset, Differential is not always the
right tool to use. The rule of thumb is that you should only send changes to
Differential if you expect humans to review the actual differences in the source
code from the web interface. This should cover the vast majority of changes but,
for example, you usually should //not// submit changes like these through
Differential:
- Committing an entire open source project to a private repo somewhere so
you can fork it or link against it.
- Committing an enormous text datafile, like a list of every English word or a
dump of a database.
- Making a trivial (e.g., find/replace or codemod) edit to 10,000 files.
You can still try submitting these kinds of changes, but you may encounter
problems getting them to work (database or connection timeouts, for example).
Differential is pretty fast and scalable, but at some point either it or the
browser will break down: you simply can't show nine million files on a webpage.
More importantly, in all these cases, the text of the changes won't be reviewed
by a human. The metadata associated with the change is what needs review (e.g.,
what are you checking in, where are you putting it, and why? Does the change
make sense? In the case of automated transformations, what script did you use?).
To get review for these types of changes, one of these strategies will usually
work better than trying to get the entire change into Differential:
- Send an email/AIM/IRC to your reviewer(s) like "Hey, I'm going to check in
the source for MySQL 9.3.1 to /full/path/to/whatever. The change is staged
in /home/whatever/path/somewhere if you want to take a look. Can I put your
name on the review?". This is best for straightforward changes. The reviewer
is not going to review MySQL's source itself, instead they are reviewing the
change metadata: which version are you checking in, why are you checking it
in, and where are you putting it? You won't be able to use "arc commit" or
"arc amend" to actually push the change. Just use "svn" or "git" and
manually edit the commit message instead. (It is normally sufficient to add
a "Reviewed By: <username>" field.)
- Create a Differential revision with only the metadata, like the script you
used to make automated changes or a text file explaining what you're doing,
and maybe a sample of some of the changes if they were automated. Include a
link to where the changes are staged so reviewers can look at the actual
changeset if they want to. This is best for more complicated changes, since
Differential can still be used for discussion and provide a permanent record
others can refer to. Once the revision is accepted, amend your local commit
(e.g. by `git commit --amend`) with the real change and push as usual.
These kinds of changes are generally rare and don't have much in common, which
is why there's no explicit support for them in Differential. If you frequently
run into cases which Differential doesn't handle, let us know what they are.

View file

@ -52,4 +52,9 @@ final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule {
return $this->getEngine()->storeText($iframe);
}
public function didMarkupText() {
CelerityAPI::getStaticResourceResponse()
->addContentSecurityPolicyURI('frame-src', 'https://www.youtube.com/');
}
}

View file

@ -687,3 +687,32 @@ ul.phui-oi-list-view .phui-oi-selectable
.phui-oi-frame {
border-color: {$blueborder};
}
.differential-revision-size {
padding: 0 4px;
border-radius: 4px;
background: {$lightgreybackground};
cursor: pointer;
}
.differential-revision-size .phui-icon-view {
margin: 0 1px 0 1px;
font-size: smaller;
color: {$blueborder};
}
.differential-revision-large {
background: {$sh-redbackground};
}
.differential-revision-large .phui-icon-view {
color: {$red};
}
.differential-revision-small {
background: {$sh-greenbackground};
}
.differential-revision-small .phui-icon-view {
color: {$green};
}

View file

@ -49,6 +49,10 @@ img.phui-image-disabled {
color: {$bluetext};
}
.phui-icon-view.invisible {
visibility: hidden;
}
/* - Icon in a Circle ------------------------------------------------------- */
.phui-icon-circle {