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

(stable) Promote 2017 Week 33

This commit is contained in:
epriestley 2017-08-22 15:30:02 -07:00
commit fb4e7a9a8d
88 changed files with 1606 additions and 1280 deletions

View file

@ -9,7 +9,7 @@ return array(
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => 'b5b51108',
'core.pkg.css' => '0e4a68ad',
'core.pkg.css' => 'fe4effd6',
'core.pkg.js' => '5d80e0db',
'darkconsole.pkg.js' => '1f9a31bc',
'differential.pkg.css' => '45951e9e',
@ -36,13 +36,13 @@ return array(
'rsrc/css/aphront/tokenizer.css' => '15d5ff71',
'rsrc/css/aphront/tooltip.css' => '173b9431',
'rsrc/css/aphront/typeahead-browse.css' => 'f2818435',
'rsrc/css/aphront/typeahead.css' => '4434bc8a',
'rsrc/css/aphront/typeahead.css' => 'a4a21016',
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
'rsrc/css/application/auth/auth.css' => '0877ed6e',
'rsrc/css/application/base/main-menu-view.css' => '16053029',
'rsrc/css/application/base/notification-menu.css' => '73fefdfa',
'rsrc/css/application/base/phui-theme.css' => '9f261c6b',
'rsrc/css/application/base/standard-page-view.css' => 'c581d2ac',
'rsrc/css/application/base/standard-page-view.css' => '34ee718b',
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
'rsrc/css/application/config/config-options.css' => 'd55ed093',
@ -75,7 +75,7 @@ return array(
'rsrc/css/application/diffusion/diffusion-readme.css' => '419dd5b6',
'rsrc/css/application/diffusion/diffusion-repository.css' => 'ee6f20ec',
'rsrc/css/application/diffusion/diffusion-source.css' => '750add59',
'rsrc/css/application/diffusion/diffusion.css' => '67bd971b',
'rsrc/css/application/diffusion/diffusion.css' => 'ceacf994',
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
'rsrc/css/application/flag/flag.css' => 'bba8f811',
@ -111,7 +111,7 @@ return array(
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae',
'rsrc/css/application/search/application-search-view.css' => '66ee5d46',
'rsrc/css/application/search/search-results.css' => '8f8e08ed',
'rsrc/css/application/search/search-results.css' => '505dd8cf',
'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
@ -165,7 +165,7 @@ return array(
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
'rsrc/css/phui/phui-info-view.css' => 'e1b4ec37',
'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0',
'rsrc/css/phui/phui-left-right.css' => 'f60c67e7',
'rsrc/css/phui/phui-left-right.css' => '75227a4d',
'rsrc/css/phui/phui-lightbox.css' => '0a035e40',
'rsrc/css/phui/phui-list.css' => '38f8c9bd',
'rsrc/css/phui/phui-object-box.css' => '9cff003c',
@ -178,12 +178,12 @@ return array(
'rsrc/css/phui/phui-status.css' => 'd5263e49',
'rsrc/css/phui/phui-tag-view.css' => 'b4719c50',
'rsrc/css/phui/phui-timeline-view.css' => 'f21db7ca',
'rsrc/css/phui/phui-two-column-view.css' => 'ae38a939',
'rsrc/css/phui/phui-two-column-view.css' => '76dcd3d4',
'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5',
'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455',
'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92',
'rsrc/css/phui/workboards/phui-workpanel.css' => 'a3a63478',
'rsrc/css/sprite-login.css' => '587d92d7',
'rsrc/css/sprite-login.css' => '396f3c3a',
'rsrc/css/sprite-tokens.css' => '9cdfd599',
'rsrc/css/syntax/syntax-default.css' => '9923583c',
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
@ -359,8 +359,8 @@ return array(
'rsrc/image/phrequent_active.png' => 'a466a8ed',
'rsrc/image/phrequent_inactive.png' => 'bfc15a69',
'rsrc/image/resize.png' => 'fd476de4',
'rsrc/image/sprite-login-X2.png' => '4abee916',
'rsrc/image/sprite-login.png' => '2b9663fd',
'rsrc/image/sprite-login-X2.png' => '308c92c4',
'rsrc/image/sprite-login.png' => '9ec54245',
'rsrc/image/sprite-tokens-X2.png' => '804a5232',
'rsrc/image/sprite-tokens.png' => 'b41d03da',
'rsrc/image/texture/card-gradient.png' => '815f26e8',
@ -546,7 +546,7 @@ return array(
'aphront-table-view-css' => 'a3aa6910',
'aphront-tokenizer-control-css' => '15d5ff71',
'aphront-tooltip-css' => '173b9431',
'aphront-typeahead-control-css' => '4434bc8a',
'aphront-typeahead-control-css' => 'a4a21016',
'application-search-view-css' => '66ee5d46',
'auth-css' => '0877ed6e',
'bulk-job-css' => 'df9c1d4a',
@ -570,7 +570,7 @@ return array(
'differential-revision-history-css' => '0e8eb855',
'differential-revision-list-css' => 'f3c47d33',
'differential-table-of-contents-css' => 'ae4b7a55',
'diffusion-css' => '67bd971b',
'diffusion-css' => 'ceacf994',
'diffusion-icons-css' => '0c15255e',
'diffusion-readme-css' => '419dd5b6',
'diffusion-repository-css' => 'ee6f20ec',
@ -798,11 +798,11 @@ return array(
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => 'c5af80a2',
'phabricator-remarkup-css' => 'cad18339',
'phabricator-search-results-css' => '8f8e08ed',
'phabricator-search-results-css' => '505dd8cf',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-slowvote-css' => 'a94b7230',
'phabricator-source-code-view-css' => 'aea41829',
'phabricator-standard-page-view' => 'c581d2ac',
'phabricator-standard-page-view' => '34ee718b',
'phabricator-textareautils' => '320810c8',
'phabricator-title' => '485aaa6c',
'phabricator-tooltip' => '358b8c04',
@ -854,7 +854,7 @@ return array(
'phui-info-view-css' => 'e1b4ec37',
'phui-inline-comment-view-css' => '65ae3bc2',
'phui-invisible-character-view-css' => '6993d9f0',
'phui-left-right-css' => 'f60c67e7',
'phui-left-right-css' => '75227a4d',
'phui-lightbox-css' => '0a035e40',
'phui-list-view-css' => '38f8c9bd',
'phui-object-box-css' => '9cff003c',
@ -874,7 +874,7 @@ return array(
'phui-tag-view-css' => 'b4719c50',
'phui-theme-css' => '9f261c6b',
'phui-timeline-view-css' => 'f21db7ca',
'phui-two-column-view-css' => 'ae38a939',
'phui-two-column-view-css' => '76dcd3d4',
'phui-workboard-color-css' => '783cdff5',
'phui-workboard-view-css' => '3bc85455',
'phui-workcard-view-css' => 'cca5fa92',
@ -897,7 +897,7 @@ return array(
'releeph-request-differential-create-dialog' => '8d8b92cd',
'releeph-request-typeahead-css' => '667a48ae',
'setup-issue-css' => 'f794cfc3',
'sprite-login-css' => '587d92d7',
'sprite-login-css' => '396f3c3a',
'sprite-tokens-css' => '9cdfd599',
'syntax-default-css' => '9923583c',
'syntax-highlighting-css' => 'cae95e89',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 B

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,013 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 934 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 776 B

View file

@ -21,11 +21,6 @@
"rule": ".login-Disqus",
"hash": "77b29d56329a3c30b79d6b6673b0e39b"
},
"login-Dropbox": {
"name": "login-Dropbox",
"rule": ".login-Dropbox",
"hash": "5eaf07ae4598227fbbba3474675d18c7"
},
"login-Facebook": {
"name": "login-Facebook",
"rule": ".login-Facebook",
@ -61,21 +56,11 @@
"rule": ".login-LDAP",
"hash": "e31df2e9faf8ca0925ef93128a82fa7a"
},
"login-Linkedin": {
"name": "login-Linkedin",
"rule": ".login-Linkedin",
"hash": "b7ee1e92c923462531f3a34093e57127"
},
"login-MediaWiki": {
"name": "login-MediaWiki",
"rule": ".login-MediaWiki",
"hash": "f1f0a9382434081a9a84e7584828c2dd"
},
"login-Openid": {
"name": "login-Openid",
"rule": ".login-Openid",
"hash": "886f65ad44435344a1fa1c13e7758155"
},
"login-PayPal": {
"name": "login-PayPal",
"rule": ".login-PayPal",
@ -84,7 +69,7 @@
"login-Phabricator": {
"name": "login-Phabricator",
"rule": ".login-Phabricator",
"hash": "d0f830803593bbcc025d7d5a29ee3ecd"
"hash": "54f5ddae4b9d138c438ec00ed42544d2"
},
"login-Slack": {
"name": "login-Slack",
@ -120,11 +105,6 @@
"name": "login-WordPressCOM",
"rule": ".login-WordPressCOM",
"hash": "9eae4205dbed0c42a18ee4f8e0fa151b"
},
"login-Yahoo": {
"name": "login-Yahoo",
"rule": ".login-Yahoo",
"hash": "f37822c769f6b8ebd1dda6b3ac89b83b"
}
},
"scales": [

View file

@ -0,0 +1,48 @@
<?php
// Migrate saved Differential revision queries from using a "<select />"
// control with hard-coded status groups for status selection to using a
// tokenizer with status functions.
$table = new PhabricatorSavedQuery();
$conn = $table->establishConnection('w');
$status_map = array(
'status-open' => array('open()'),
'status-closed' => array('closed()'),
'status-accepted' => array('accepted'),
'status-needs-review' => array('needs-review'),
'status-needs-revision' => array('needs-revision'),
'status-abandoned' => array('abandoned'),
);
foreach (new LiskMigrationIterator($table) as $query) {
if ($query->getEngineClassName() !== 'DifferentialRevisionSearchEngine') {
// This isn't a revision query.
continue;
}
$parameters = $query->getParameters();
$status = idx($parameters, 'status');
if (!$status) {
// This query didn't specify a "status" value.
continue;
}
if (!isset($status_map[$status])) {
// The "status" value is unknown, or does not correspond to a
// modern "status" constraint.
continue;
}
$parameters['statuses'] = $status_map[$status];
queryfx(
$conn,
'UPDATE %T SET parameters = %s WHERE id = %d',
$table->getTableName(),
phutil_json_encode($parameters),
$query->getID());
}

View file

@ -0,0 +1,17 @@
UPDATE {$NAMESPACE}_differential.differential_revision
SET status = "needs-review" WHERE status = "0";
UPDATE {$NAMESPACE}_differential.differential_revision
SET status = "needs-revision" WHERE status = "1";
UPDATE {$NAMESPACE}_differential.differential_revision
SET status = "accepted" WHERE status = "2";
UPDATE {$NAMESPACE}_differential.differential_revision
SET status = "published" WHERE status = "3";
UPDATE {$NAMESPACE}_differential.differential_revision
SET status = "abandoned" WHERE status = "4";
UPDATE {$NAMESPACE}_differential.differential_revision
SET status = "changes-planned" WHERE status = "5";

View file

@ -0,0 +1,38 @@
<?php
$map = array(
'0' => 'needs-review',
'1' => 'needs-revision',
'2' => 'accepted',
'3' => 'published',
'4' => 'abandoned',
'5' => 'changes-planned',
);
$table = new DifferentialTransaction();
$conn = $table->establishConnection('w');
foreach (new LiskMigrationIterator($table) as $xaction) {
$type = $xaction->getTransactionType();
if (($type != 'differential:status') &&
($type != 'differential.revision.status')) {
continue;
}
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$old = idx($map, $old, $old);
$new = idx($map, $new, $new);
queryfx(
$conn,
'UPDATE %T SET transactionType = %s, oldValue = %s, newValue = %s
WHERE id = %d',
$table->getTableName(),
'differential.revision.status',
json_encode($old),
json_encode($new),
$xaction->getID());
}

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_phame.phame_post
ADD views INTEGER NOT NULL;

View file

@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_phame.phame_post
SET views = 0;

View file

@ -445,7 +445,6 @@ phutil_register_library_map(array(
'DifferentialExactUserFunctionDatasource' => 'applications/differential/typeahead/DifferentialExactUserFunctionDatasource.php',
'DifferentialFieldParseException' => 'applications/differential/exception/DifferentialFieldParseException.php',
'DifferentialFieldValidationException' => 'applications/differential/exception/DifferentialFieldValidationException.php',
'DifferentialFindConduitAPIMethod' => 'applications/differential/conduit/DifferentialFindConduitAPIMethod.php',
'DifferentialGetAllDiffsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetAllDiffsConduitAPIMethod.php',
'DifferentialGetCommitMessageConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php',
'DifferentialGetCommitPathsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetCommitPathsConduitAPIMethod.php',
@ -521,6 +520,7 @@ phutil_register_library_map(array(
'DifferentialRevisionAuthorProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorProjectsHeraldField.php',
'DifferentialRevisionCloseDetailsController' => 'applications/differential/controller/DifferentialRevisionCloseDetailsController.php',
'DifferentialRevisionCloseTransaction' => 'applications/differential/xaction/DifferentialRevisionCloseTransaction.php',
'DifferentialRevisionClosedStatusDatasource' => 'applications/differential/typeahead/DifferentialRevisionClosedStatusDatasource.php',
'DifferentialRevisionCommandeerTransaction' => 'applications/differential/xaction/DifferentialRevisionCommandeerTransaction.php',
'DifferentialRevisionContentAddedHeraldField' => 'applications/differential/herald/DifferentialRevisionContentAddedHeraldField.php',
'DifferentialRevisionContentHeraldField' => 'applications/differential/herald/DifferentialRevisionContentHeraldField.php',
@ -548,6 +548,7 @@ phutil_register_library_map(array(
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php',
'DifferentialRevisionOpenStatusDatasource' => 'applications/differential/typeahead/DifferentialRevisionOpenStatusDatasource.php',
'DifferentialRevisionOperationController' => 'applications/differential/controller/DifferentialRevisionOperationController.php',
'DifferentialRevisionPHIDType' => 'applications/differential/phid/DifferentialRevisionPHIDType.php',
'DifferentialRevisionPackageHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageHeraldField.php',
@ -572,6 +573,9 @@ phutil_register_library_map(array(
'DifferentialRevisionSearchConduitAPIMethod' => 'applications/differential/conduit/DifferentialRevisionSearchConduitAPIMethod.php',
'DifferentialRevisionSearchEngine' => 'applications/differential/query/DifferentialRevisionSearchEngine.php',
'DifferentialRevisionStatus' => 'applications/differential/constants/DifferentialRevisionStatus.php',
'DifferentialRevisionStatusDatasource' => 'applications/differential/typeahead/DifferentialRevisionStatusDatasource.php',
'DifferentialRevisionStatusFunctionDatasource' => 'applications/differential/typeahead/DifferentialRevisionStatusFunctionDatasource.php',
'DifferentialRevisionStatusTransaction' => 'applications/differential/xaction/DifferentialRevisionStatusTransaction.php',
'DifferentialRevisionSummaryHeraldField' => 'applications/differential/herald/DifferentialRevisionSummaryHeraldField.php',
'DifferentialRevisionSummaryTransaction' => 'applications/differential/xaction/DifferentialRevisionSummaryTransaction.php',
'DifferentialRevisionTestPlanTransaction' => 'applications/differential/xaction/DifferentialRevisionTestPlanTransaction.php',
@ -772,6 +776,7 @@ phutil_register_library_map(array(
'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php',
'DiffusionPathTreeController' => 'applications/diffusion/controller/DiffusionPathTreeController.php',
'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php',
'DiffusionPatternSearchView' => 'applications/diffusion/view/DiffusionPatternSearchView.php',
'DiffusionPhpExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPhpExternalSymbolsSource.php',
'DiffusionPreCommitContentAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentAffectedFilesHeraldField.php',
'DiffusionPreCommitContentAuthorHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentAuthorHeraldField.php',
@ -4412,6 +4417,7 @@ phutil_register_library_map(array(
'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php',
'PhamePostTransactionType' => 'applications/phame/xaction/PhamePostTransactionType.php',
'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php',
'PhamePostViewsTransaction' => 'applications/phame/xaction/PhamePostViewsTransaction.php',
'PhamePostVisibilityTransaction' => 'applications/phame/xaction/PhamePostVisibilityTransaction.php',
'PhameSchemaSpec' => 'applications/phame/storage/PhameSchemaSpec.php',
'PhameSite' => 'applications/phame/site/PhameSite.php',
@ -5415,7 +5421,6 @@ phutil_register_library_map(array(
'DifferentialExactUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DifferentialFieldParseException' => 'Exception',
'DifferentialFieldValidationException' => 'Exception',
'DifferentialFindConduitAPIMethod' => 'DifferentialConduitAPIMethod',
'DifferentialGetAllDiffsConduitAPIMethod' => 'DifferentialConduitAPIMethod',
'DifferentialGetCommitMessageConduitAPIMethod' => 'DifferentialConduitAPIMethod',
'DifferentialGetCommitPathsConduitAPIMethod' => 'DifferentialConduitAPIMethod',
@ -5514,6 +5519,7 @@ phutil_register_library_map(array(
'DifferentialRevisionAuthorProjectsHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionCloseDetailsController' => 'DifferentialController',
'DifferentialRevisionCloseTransaction' => 'DifferentialRevisionActionTransaction',
'DifferentialRevisionClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource',
'DifferentialRevisionCommandeerTransaction' => 'DifferentialRevisionActionTransaction',
'DifferentialRevisionContentAddedHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionContentHeraldField' => 'DifferentialRevisionHeraldField',
@ -5541,6 +5547,7 @@ phutil_register_library_map(array(
'DifferentialRevisionListController' => 'DifferentialController',
'DifferentialRevisionListView' => 'AphrontView',
'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver',
'DifferentialRevisionOpenStatusDatasource' => 'PhabricatorTypeaheadDatasource',
'DifferentialRevisionOperationController' => 'DifferentialController',
'DifferentialRevisionPHIDType' => 'PhabricatorPHIDType',
'DifferentialRevisionPackageHeraldField' => 'DifferentialRevisionHeraldField',
@ -5565,6 +5572,9 @@ phutil_register_library_map(array(
'DifferentialRevisionSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'DifferentialRevisionSearchEngine' => 'PhabricatorApplicationSearchEngine',
'DifferentialRevisionStatus' => 'Phobject',
'DifferentialRevisionStatusDatasource' => 'PhabricatorTypeaheadDatasource',
'DifferentialRevisionStatusFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DifferentialRevisionStatusTransaction' => 'DifferentialRevisionTransactionType',
'DifferentialRevisionSummaryHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionSummaryTransaction' => 'DifferentialRevisionTransactionType',
'DifferentialRevisionTestPlanTransaction' => 'DifferentialRevisionTransactionType',
@ -5768,6 +5778,7 @@ phutil_register_library_map(array(
'DiffusionPathQueryTestCase' => 'PhabricatorTestCase',
'DiffusionPathTreeController' => 'DiffusionController',
'DiffusionPathValidateController' => 'DiffusionController',
'DiffusionPatternSearchView' => 'DiffusionView',
'DiffusionPhpExternalSymbolsSource' => 'DiffusionExternalSymbolsSource',
'DiffusionPreCommitContentAffectedFilesHeraldField' => 'DiffusionPreCommitContentHeraldField',
'DiffusionPreCommitContentAuthorHeraldField' => 'DiffusionPreCommitContentHeraldField',
@ -10031,6 +10042,7 @@ phutil_register_library_map(array(
'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhamePostTransactionType' => 'PhabricatorModularTransactionType',
'PhamePostViewController' => 'PhameLiveController',
'PhamePostViewsTransaction' => 'PhamePostTransactionType',
'PhamePostVisibilityTransaction' => 'PhamePostTransactionType',
'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhameSite' => 'PhabricatorSite',

View file

@ -93,7 +93,7 @@ final class PhabricatorAuthSSHKeyEditController
try {
$editor->applyTransactions($key, $xactions);
return id(new AphrontRedirectResponse())->setURI($key->getURI());
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$e_name = $ex->getShortMessage($type_name);

View file

@ -50,9 +50,15 @@ final class PhabricatorDataCacheSpec extends PhabricatorCacheSpec {
->setVersion(phpversion('apcu'));
if (ini_get('apc.enabled')) {
if (function_exists('apcu_clear_cache')) {
$clear_callback = 'apcu_clear_cache';
} else {
$clear_callback = 'apc_clear_cache';
}
$this
->setIsEnabled(true)
->setClearCacheCallback('apc_clear_cache');
->setClearCacheCallback($clear_callback);
$this->initAPCCommonSpec();
} else {
$this->setIsEnabled(false);

View file

@ -7,6 +7,12 @@ final class PhabricatorElasticsearchSetupCheck extends PhabricatorSetupCheck {
}
protected function executeChecks() {
// TODO: Avoid fataling if we don't have a master database configured
// but have the MySQL search index configured. See T12965.
if (PhabricatorEnv::isReadOnly()) {
return;
}
$services = PhabricatorSearchService::getAllServices();
foreach ($services as $service) {

View file

@ -9,7 +9,13 @@ final class PhabricatorMySQLSetupCheck extends PhabricatorSetupCheck {
protected function executeChecks() {
$refs = PhabricatorDatabaseRef::getActiveDatabaseRefs();
foreach ($refs as $ref) {
try {
$this->executeRefChecks($ref);
} catch (AphrontConnectionQueryException $ex) {
// If we're unable to connect to a host, just skip the checks for it.
// This can happen if we're restarting during a cluster incident. See
// T12966 for discussion.
}
}
}

View file

@ -52,8 +52,9 @@ final class DifferentialCloseConduitAPIMethod
$xactions = array();
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
->setNewValue(DifferentialAction::ACTION_CLOSE);
->setTransactionType(
DifferentialRevisionCloseTransaction::TRANSACTIONTYPE)
->setNewValue(true);
$content_source = $request->newContentSource();

View file

@ -63,6 +63,7 @@ final class DifferentialCreateCommentConduitAPIMethod
'resign' => DifferentialRevisionResignTransaction::TRANSACTIONTYPE,
'request_review' =>
DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE,
'rethink' => DifferentialRevisionPlanChangesTransaction::TRANSACTIONTYPE,
);
$action = $request->getValue('action');
@ -76,9 +77,10 @@ final class DifferentialCreateCommentConduitAPIMethod
case 'none':
break;
default:
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
->setNewValue($action);
throw new Exception(
pht(
'Unsupported action "%s".',
$action));
break;
}
}

View file

@ -1,99 +0,0 @@
<?php
final class DifferentialFindConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.find';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht("Replaced by '%s'.", 'differential.query');
}
public function getMethodDescription() {
return pht('Query Differential revisions which match certain criteria.');
}
protected function defineParamTypes() {
$types = array(
'open',
'committable',
'revision-ids',
'phids',
);
return array(
'query' => 'required '.$this->formatStringConstants($types),
'guids' => 'required nonempty list<guids>',
);
}
protected function defineReturnType() {
return 'nonempty list<dict>';
}
protected function execute(ConduitAPIRequest $request) {
$type = $request->getValue('query');
$guids = $request->getValue('guids');
$results = array();
if (!$guids) {
return $results;
}
$query = id(new DifferentialRevisionQuery())
->setViewer($request->getUser());
switch ($type) {
case 'open':
$query
->withStatus(DifferentialLegacyQuery::STATUS_OPEN)
->withAuthors($guids);
break;
case 'committable':
$query
->withStatus(DifferentialLegacyQuery::STATUS_ACCEPTED)
->withAuthors($guids);
break;
case 'revision-ids':
$query
->withIDs($guids);
break;
case 'owned':
$query->withAuthors($guids);
break;
case 'phids':
$query
->withPHIDs($guids);
break;
}
$revisions = $query->execute();
foreach ($revisions as $revision) {
$diff = $revision->loadActiveDiff();
if (!$diff) {
continue;
}
$id = $revision->getID();
$results[] = array(
'id' => $id,
'phid' => $revision->getPHID(),
'name' => $revision->getTitle(),
'uri' => PhabricatorEnv::getProductionURI('/D'.$id),
'dateCreated' => $revision->getDateCreated(),
'authorPHID' => $revision->getAuthorPHID(),
'statusName' => $revision->getStatusDisplayName(),
'sourcePath' => $diff->getSourcePath(),
);
}
return $results;
}
}

View file

@ -82,7 +82,7 @@ final class DifferentialGetRevisionConduitAPIMethod
'authorPHID' => $revision->getAuthorPHID(),
'uri' => PhabricatorEnv::getURI('/D'.$revision->getID()),
'title' => $revision->getTitle(),
'status' => $revision->getStatus(),
'status' => $revision->getLegacyRevisionStatus(),
'statusName' => $revision->getStatusDisplayName(),
'summary' => $revision->getSummary(),
'testPlan' => $revision->getTestPlan(),

View file

@ -150,7 +150,10 @@ final class DifferentialQueryConduitAPIMethod
}
if ($status) {
$query->withStatus($status);
$statuses = DifferentialLegacyQuery::getModernValues($status);
if ($statuses) {
$query->withStatuses($statuses);
}
}
if ($order) {
$query->setOrder($order);
@ -215,7 +218,7 @@ final class DifferentialQueryConduitAPIMethod
'dateCreated' => $revision->getDateCreated(),
'dateModified' => $revision->getDateModified(),
'authorPHID' => $revision->getAuthorPHID(),
'status' => $revision->getStatus(),
'status' => $revision->getLegacyRevisionStatus(),
'statusName' => $revision->getStatusDisplayName(),
'properties' => $revision->getProperties(),
'branch' => $diff->getBranch(),

View file

@ -15,7 +15,7 @@ final class DifferentialLegacyQuery
return array_keys(self::getMap());
}
public static function getQueryValues($status) {
public static function getModernValues($status) {
if ($status === self::STATUS_ANY) {
return null;
}
@ -28,18 +28,7 @@ final class DifferentialLegacyQuery
$status));
}
$values = array();
foreach ($map[$status] as $status_constant) {
$status_object = DifferentialRevisionStatus::newForStatus(
$status_constant);
$legacy_key = $status_object->getLegacyKey();
if ($legacy_key !== null) {
$values[] = $legacy_key;
}
}
return $values;
return $map[$status];
}
private static function getMap() {

View file

@ -32,6 +32,18 @@ final class DifferentialRevisionStatus extends Phobject {
return idx($this->spec, 'color.tag', 'bluegrey');
}
public function getTimelineIcon() {
return idx($this->spec, 'icon.timeline');
}
public function getTimelineColor() {
return idx($this->spec, 'color.timeline');
}
public function getANSIColor() {
return idx($this->spec, 'color.ansi');
}
public function getDisplayName() {
return idx($this->spec, 'name');
}
@ -52,6 +64,10 @@ final class DifferentialRevisionStatus extends Phobject {
return ($this->key === self::NEEDS_REVIEW);
}
public function isNeedsRevision() {
return ($this->key === self::NEEDS_REVISION);
}
public function isPublished() {
return ($this->key === self::PUBLISHED);
}
@ -72,22 +88,11 @@ final class DifferentialRevisionStatus extends Phobject {
return $result;
}
public static function newForLegacyStatus($legacy_status) {
$result = new self();
public static function getAll() {
$result = array();
$map = self::getMap();
foreach ($map as $key => $spec) {
if (!isset($spec['legacy'])) {
continue;
}
if ($spec['legacy'] != $legacy_status) {
continue;
}
$result->key = $key;
$result->spec = $spec;
break;
foreach (self::getMap() as $key => $spec) {
$result[$key] = self::newForStatus($key);
}
return $result;
@ -102,19 +107,23 @@ final class DifferentialRevisionStatus extends Phobject {
'name' => pht('Needs Review'),
'legacy' => 0,
'icon' => 'fa-code',
'icon.timeline' => 'fa-undo',
'closed' => false,
'color.icon' => 'grey',
'color.tag' => 'bluegrey',
'color.ansi' => 'magenta',
'color.timeline' => 'orange',
),
self::NEEDS_REVISION => array(
'name' => pht('Needs Revision'),
'legacy' => 1,
'icon' => 'fa-refresh',
'icon.timeline' => 'fa-times',
'closed' => false,
'color.icon' => 'red',
'color.tag' => 'red',
'color.ansi' => 'red',
'color.timeline' => 'red',
),
self::CHANGES_PLANNED => array(
'name' => pht('Changes Planned'),
@ -129,10 +138,12 @@ final class DifferentialRevisionStatus extends Phobject {
'name' => pht('Accepted'),
'legacy' => 2,
'icon' => 'fa-check',
'icon.timeline' => 'fa-check',
'closed' => $close_on_accept,
'color.icon' => 'green',
'color.tag' => 'green',
'color.ansi' => 'green',
'color.timeline' => 'green',
),
self::PUBLISHED => array(
'name' => pht('Closed'),

View file

@ -177,7 +177,7 @@ final class DifferentialDiffViewController extends DifferentialController {
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withAuthors(array($viewer->getPHID()))
->withStatus(DifferentialLegacyQuery::STATUS_OPEN)
->withIsOpen(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,

View file

@ -808,7 +808,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
$query = id(new DifferentialRevisionQuery())
->setViewer($this->getRequest()->getUser())
->withStatus(DifferentialLegacyQuery::STATUS_OPEN)
->withIsOpen(true)
->withUpdatedEpochBetween($recent, null)
->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED)
->setLimit(10)

View file

@ -69,9 +69,7 @@ final class DifferentialTransactionEditor
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
$types[] = PhabricatorTransactions::TYPE_INLINESTATE;
$types[] = DifferentialTransaction::TYPE_ACTION;
$types[] = DifferentialTransaction::TYPE_INLINE;
$types[] = DifferentialTransaction::TYPE_STATUS;
$types[] = DifferentialTransaction::TYPE_UPDATE;
return $types;
@ -82,8 +80,6 @@ final class DifferentialTransactionEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case DifferentialTransaction::TYPE_ACTION:
return null;
case DifferentialTransaction::TYPE_INLINE:
return null;
case DifferentialTransaction::TYPE_UPDATE:
@ -102,7 +98,6 @@ final class DifferentialTransactionEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case DifferentialTransaction::TYPE_ACTION:
case DifferentialTransaction::TYPE_UPDATE:
return $xaction->getNewValue();
case DifferentialTransaction::TYPE_INLINE:
@ -121,28 +116,6 @@ final class DifferentialTransactionEditor
switch ($xaction->getTransactionType()) {
case DifferentialTransaction::TYPE_INLINE:
return $xaction->hasComment();
case DifferentialTransaction::TYPE_ACTION:
$status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
$status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED;
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
$status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION;
$status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED;
$action_type = $xaction->getNewValue();
switch ($action_type) {
case DifferentialAction::ACTION_CLOSE:
return ($object->getStatus() != $status_closed);
case DifferentialAction::ACTION_ABANDON:
return ($object->getStatus() != $status_abandoned);
case DifferentialAction::ACTION_RECLAIM:
return ($object->getStatus() == $status_abandoned);
case DifferentialAction::ACTION_REOPEN:
return ($object->getStatus() == $status_closed);
case DifferentialAction::ACTION_RETHINK:
return ($object->getStatus() != $status_plan);
case DifferentialAction::ACTION_CLAIM:
return ($actor_phid != $object->getAuthorPHID());
}
}
return parent::transactionHasEffect($object, $xaction);
@ -152,23 +125,16 @@ final class DifferentialTransactionEditor
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
$status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION;
$status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED;
$status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED;
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
switch ($xaction->getTransactionType()) {
case DifferentialTransaction::TYPE_INLINE:
return;
case DifferentialTransaction::TYPE_UPDATE:
if (!$this->getIsCloseByCommit()) {
switch ($object->getStatus()) {
case $status_revision:
case $status_plan:
case $status_abandoned:
$object->setStatus($status_review);
break;
if ($object->isNeedsRevision() ||
$object->isChangePlanned() ||
$object->isAbandoned()) {
$object->setModernRevisionStatus(
DifferentialRevisionStatus::NEEDS_REVIEW);
}
}
@ -184,38 +150,6 @@ final class DifferentialTransactionEditor
// TODO: Update the `diffPHID` once we add that.
return;
case DifferentialTransaction::TYPE_ACTION:
switch ($xaction->getNewValue()) {
case DifferentialAction::ACTION_ABANDON:
$object->setStatus(ArcanistDifferentialRevisionStatus::ABANDONED);
return;
case DifferentialAction::ACTION_RETHINK:
$object->setStatus($status_plan);
return;
case DifferentialAction::ACTION_RECLAIM:
$object->setStatus($status_review);
return;
case DifferentialAction::ACTION_REOPEN:
$object->setStatus($status_review);
return;
case DifferentialAction::ACTION_CLOSE:
$old_status = $object->getStatus();
$object->setStatus(ArcanistDifferentialRevisionStatus::CLOSED);
$was_accepted = ($old_status == $status_accepted);
$object->setProperty(
DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED,
$was_accepted);
return;
case DifferentialAction::ACTION_CLAIM:
$object->setAuthorPHID($this->getActingAsPHID());
return;
default:
throw new Exception(
pht(
'Differential action "%s" is not a valid action!',
$xaction->getNewValue()));
}
break;
}
return parent::applyCustomInternalTransaction($object, $xaction);
@ -255,9 +189,6 @@ final class DifferentialTransactionEditor
$actor_phid = $this->getActingAsPHID();
$type_edge = PhabricatorTransactions::TYPE_EDGE;
$status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED;
$edge_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
$edge_ref_task = DifferentialRevisionHasTaskEdgeType::EDGECONST;
$is_sticky_accept = PhabricatorEnv::getEnvConfig(
@ -280,7 +211,7 @@ final class DifferentialTransactionEditor
case DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE:
$downgrade_rejects = true;
if ((!$is_sticky_accept) ||
($object->getStatus() != $status_plan)) {
(!$object->isChangePlanned())) {
// If the old state isn't "changes planned", downgrade the accepts.
// This exception allows an accepted revision to go through
// "Plan Changes" -> "Request Review" and return to "accepted" if
@ -297,48 +228,6 @@ final class DifferentialTransactionEditor
$old_accept = DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER;
$old_reject = DifferentialReviewerStatus::STATUS_REJECTED_OLDER;
if ($downgrade_rejects || $downgrade_accepts) {
// When a revision is updated, change all "reject" to "rejected older
// revision". This means we won't immediately push the update back into
// "needs review", but outstanding rejects will still block it from
// moving to "accepted".
// We also do this for "Request Review", even though the diff is not
// updated directly. Essentially, this acts like an update which doesn't
// actually change the diff text.
$edits = array();
foreach ($object->getReviewers() as $reviewer) {
if ($downgrade_rejects) {
if ($reviewer->getReviewerStatus() == $new_reject) {
$edits[$reviewer->getReviewerPHID()] = array(
'data' => array(
'status' => $old_reject,
),
);
}
}
if ($downgrade_accepts) {
if ($reviewer->getReviewerStatus() == $new_accept) {
$edits[$reviewer->getReviewerPHID()] = array(
'data' => array(
'status' => $old_accept,
),
);
}
}
}
if ($edits) {
$results[] = id(new DifferentialTransaction())
->setTransactionType($type_edge)
->setMetadataValue('edge:type', $edge_reviewer)
->setIgnoreOnNoEffect(true)
->setNewValue(array('+' => $edits));
}
}
$downgrade = array();
if ($downgrade_accepts) {
$downgrade[] = DifferentialReviewerStatus::STATUS_ACCEPTED;
@ -397,56 +286,9 @@ final class DifferentialTransactionEditor
}
break;
case PhabricatorTransactions::TYPE_COMMENT:
// When a user leaves a comment, upgrade their reviewer status from
// "added" to "commented" if they're also a reviewer. We may further
// upgrade this based on other actions in the transaction group.
if ($this->hasReviewTransaction) {
// If we're also applying a review transaction, skip this.
break;
}
$status_added = DifferentialReviewerStatus::STATUS_ADDED;
$status_commented = DifferentialReviewerStatus::STATUS_COMMENTED;
$data = array(
'status' => $status_commented,
);
$edits = array();
foreach ($object->getReviewers() as $reviewer) {
if ($reviewer->getReviewerPHID() == $actor_phid) {
if ($reviewer->getReviewerStatus() == $status_added) {
$edits[$actor_phid] = array(
'data' => $data,
);
}
}
}
if ($edits) {
$results[] = id(new DifferentialTransaction())
->setTransactionType($type_edge)
->setMetadataValue('edge:type', $edge_reviewer)
->setIgnoreOnNoEffect(true)
->setNewValue(array('+' => $edits));
}
break;
case DifferentialRevisionCommandeerTransaction::TRANSACTIONTYPE:
$is_commandeer = true;
break;
case DifferentialTransaction::TYPE_ACTION:
$action_type = $xaction->getNewValue();
switch ($action_type) {
case DifferentialAction::ACTION_CLAIM:
$is_commandeer = true;
break;
}
break;
}
if ($is_commandeer) {
@ -456,7 +298,6 @@ final class DifferentialTransactionEditor
if (!$this->didExpandInlineState) {
switch ($xaction->getTransactionType()) {
case PhabricatorTransactions::TYPE_COMMENT:
case DifferentialTransaction::TYPE_ACTION:
case DifferentialTransaction::TYPE_UPDATE:
case DifferentialTransaction::TYPE_INLINE:
$this->didExpandInlineState = true;
@ -502,8 +343,6 @@ final class DifferentialTransactionEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case DifferentialTransaction::TYPE_ACTION:
return;
case DifferentialTransaction::TYPE_INLINE:
$reply = $xaction->getComment()->getReplyToComment();
if ($reply && !$reply->getHasReplies()) {
@ -575,33 +414,6 @@ final class DifferentialTransactionEditor
return parent::applyBuiltinExternalTransaction($object, $xaction);
}
protected function mergeEdgeData($type, array $u, array $v) {
$result = parent::mergeEdgeData($type, $u, $v);
switch ($type) {
case DifferentialRevisionHasReviewerEdgeType::EDGECONST:
// When the same reviewer has their status updated by multiple
// transactions, we want the strongest status to win. An example of
// this is when a user adds a comment and also accepts a revision which
// they are a reviewer on. The comment creates a "commented" status,
// while the accept creates an "accepted" status. Since accept is
// stronger, it should win and persist.
$u_status = idx($u, 'status');
$v_status = idx($v, 'status');
$u_str = DifferentialReviewerStatus::getStatusStrength($u_status);
$v_str = DifferentialReviewerStatus::getStatusStrength($v_status);
if ($u_str > $v_str) {
$result['status'] = $u_status;
} else {
$result['status'] = $v_status;
}
break;
}
return $result;
}
protected function applyFinalEffects(
PhabricatorLiskDAO $object,
array $xactions) {
@ -641,19 +453,25 @@ final class DifferentialTransactionEditor
}
}
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
$status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION;
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
$xactions = $this->updateReviewStatus($object, $xactions);
$this->markReviewerComments($object, $xactions);
$is_sticky_accept = PhabricatorEnv::getEnvConfig(
'differential.sticky-accept');
return $xactions;
}
private function updateReviewStatus(
DifferentialRevision $revision,
array $xactions) {
$was_accepted = $revision->isAccepted();
$was_revision = $revision->isNeedsRevision();
$was_review = $revision->isNeedsReview();
if (!$was_accepted && !$was_revision && !$was_review) {
// Revisions can't transition out of other statuses (like closed or
// abandoned) as a side effect of reviewer status changes.
return $xactions;
}
$old_status = $object->getStatus();
$active_diff = $object->getActiveDiff();
switch ($old_status) {
case $status_accepted:
case $status_revision:
case $status_review:
// Try to move a revision to "accepted". We look for:
//
// - at least one accepting reviewer who is a user; and
@ -665,7 +483,9 @@ final class DifferentialTransactionEditor
$has_rejecting_reviewer = false;
$has_rejecting_older_reviewer = false;
$has_blocking_reviewer = false;
foreach ($object->getReviewers() as $reviewer) {
$active_diff = $revision->getActiveDiff();
foreach ($revision->getReviewers() as $reviewer) {
$reviewer_status = $reviewer->getReviewerStatus();
switch ($reviewer_status) {
case DifferentialReviewerStatus::STATUS_REJECTED:
@ -698,44 +518,47 @@ final class DifferentialTransactionEditor
!$has_rejecting_reviewer &&
!$has_rejecting_older_reviewer &&
!$has_blocking_reviewer) {
$new_status = $status_accepted;
$new_status = DifferentialRevisionStatus::ACCEPTED;
} else if ($has_rejecting_reviewer) {
// This isn't accepted, and there's at least one rejecting reviewer,
// so the revision needs changes. This usually happens after a
// "reject".
$new_status = $status_revision;
} else if ($old_status == $status_accepted) {
$new_status = DifferentialRevisionStatus::NEEDS_REVISION;
} else if ($was_accepted) {
// This revision was accepted, but it no longer satisfies the
// conditions for acceptance. This usually happens after an accepting
// reviewer resigns or is removed.
$new_status = $status_review;
$new_status = DifferentialRevisionStatus::NEEDS_REVIEW;
}
if ($new_status === null) {
return $xactions;
}
$old_status = $revision->getModernRevisionStatus();
if ($new_status == $old_status) {
return $xactions;
}
if ($new_status !== null && ($new_status != $old_status)) {
$xaction = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_STATUS)
->setTransactionType(
DifferentialRevisionStatusTransaction::TRANSACTIONTYPE)
->setOldValue($old_status)
->setNewValue($new_status);
$xaction = $this->populateTransaction($object, $xaction)->save();
$xaction = $this->populateTransaction($revision, $xaction)
->save();
$xactions[] = $xaction;
$object->setStatus($new_status)->save();
}
break;
default:
// Revisions can't transition out of other statuses (like closed or
// abandoned) as a side effect of reviewer status changes.
break;
}
$this->markReviewerComments($object, $xactions);
// Save the status adjustment we made earlier.
$revision
->setModernRevisionStatus($new_status)
->save();
return $xactions;
}
protected function validateTransaction(
PhabricatorLiskDAO $object,
$type,
@ -748,40 +571,6 @@ final class DifferentialTransactionEditor
foreach ($xactions as $xaction) {
switch ($type) {
case PhabricatorTransactions::TYPE_EDGE:
switch ($xaction->getMetadataValue('edge:type')) {
case DifferentialRevisionHasReviewerEdgeType::EDGECONST:
// Prevent the author from becoming a reviewer.
// NOTE: This is pretty gross, but this restriction is unusual.
// If we end up with too much more of this, we should try to clean
// this up -- maybe by moving validation to after transactions
// are adjusted (so we can just examine the final value) or adding
// a second phase there?
$author_phid = $object->getAuthorPHID();
$new = $xaction->getNewValue();
$add = idx($new, '+', array());
$eq = idx($new, '=', array());
$phids = array_keys($add + $eq);
foreach ($phids as $phid) {
if (($phid == $author_phid) &&
!$allow_self_accept &&
!$xaction->getIsCommandeerSideEffect()) {
$errors[] =
new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
pht('The author of a revision can not be a reviewer.'),
$xaction);
}
}
break;
}
break;
case DifferentialTransaction::TYPE_UPDATE:
$diff = $this->loadDiff($xaction->getNewValue());
if (!$diff) {
@ -801,172 +590,12 @@ final class DifferentialTransactionEditor
$xaction);
}
break;
case DifferentialTransaction::TYPE_ACTION:
$error = $this->validateDifferentialAction(
$object,
$type,
$xaction,
$xaction->getNewValue());
if ($error) {
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
$error,
$xaction);
}
break;
}
}
return $errors;
}
private function validateDifferentialAction(
DifferentialRevision $revision,
$type,
DifferentialTransaction $xaction,
$action) {
$author_phid = $revision->getAuthorPHID();
$actor_phid = $this->getActingAsPHID();
$actor_is_author = ($author_phid == $actor_phid);
$config_abandon_key = 'differential.always-allow-abandon';
$always_allow_abandon = PhabricatorEnv::getEnvConfig($config_abandon_key);
$config_close_key = 'differential.always-allow-close';
$always_allow_close = PhabricatorEnv::getEnvConfig($config_close_key);
$config_reopen_key = 'differential.allow-reopen';
$allow_reopen = PhabricatorEnv::getEnvConfig($config_reopen_key);
$config_self_accept_key = 'differential.allow-self-accept';
$allow_self_accept = PhabricatorEnv::getEnvConfig($config_self_accept_key);
$revision_status = $revision->getStatus();
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
$status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED;
$status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
switch ($action) {
case DifferentialAction::ACTION_CLAIM:
// You can claim a revision if you're not the owner. If you are, this
// is a no-op rather than invalid.
if ($revision_status == $status_closed) {
return pht(
'You can not commandeer this revision because it has already been '.
'closed.');
}
break;
case DifferentialAction::ACTION_ABANDON:
if (!$actor_is_author && !$always_allow_abandon) {
return pht(
'You can not abandon this revision because you do not own it. '.
'You can only abandon revisions you own.');
}
if ($revision_status == $status_closed) {
return pht(
'You can not abandon this revision because it has already been '.
'closed.');
}
// NOTE: Abandons of already-abandoned revisions are treated as no-op
// instead of invalid. Other abandons are OK.
break;
case DifferentialAction::ACTION_RECLAIM:
if (!$actor_is_author) {
return pht(
'You can not reclaim this revision because you do not own '.
'it. You can only reclaim revisions you own.');
}
if ($revision_status == $status_closed) {
return pht(
'You can not reclaim this revision because it has already been '.
'closed.');
}
// NOTE: Reclaims of other non-abandoned revisions are treated as no-op
// instead of invalid.
break;
case DifferentialAction::ACTION_REOPEN:
if (!$allow_reopen) {
return pht(
'The reopen action is not enabled on this Phabricator install. '.
'Adjust your configuration to enable it.');
}
// NOTE: If the revision is not closed, this is caught as a no-op
// instead of an invalid transaction.
break;
case DifferentialAction::ACTION_RETHINK:
if (!$actor_is_author) {
return pht(
'You can not plan changes to this revision because you do not '.
'own it. To plan changes to a revision, you must be its owner.');
}
switch ($revision_status) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
// These are OK.
break;
case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED:
// Let this through, it's a no-op.
break;
case ArcanistDifferentialRevisionStatus::ABANDONED:
return pht(
'You can not plan changes to this revision because it has '.
'been abandoned.');
case ArcanistDifferentialRevisionStatus::CLOSED:
return pht(
'You can not plan changes to this revision because it has '.
'already been closed.');
default:
throw new Exception(
pht(
'Encountered unexpected revision status ("%s") when '.
'validating "%s" action.',
$revision_status,
$action));
}
break;
case DifferentialAction::ACTION_CLOSE:
// We force revisions closed when we discover a corresponding commit.
// In this case, revisions are allowed to transition to closed from
// any state. This is an automated action taken by the daemons.
if (!$this->getIsCloseByCommit()) {
if (!$actor_is_author && !$always_allow_close) {
return pht(
'You can not close this revision because you do not own it. To '.
'close a revision, you must be its owner.');
}
if ($revision_status != $status_accepted) {
return pht(
'You can not close this revision because it has not been '.
'accepted. You can only close accepted revisions.');
}
}
break;
}
return null;
}
protected function sortTransactions(array $xactions) {
$xactions = parent::sortTransactions($xactions);
@ -1374,14 +1003,6 @@ final class DifferentialTransactionEditor
// When users commandeer revisions, we may need to trigger
// signatures or author-based rules.
return true;
case DifferentialTransaction::TYPE_ACTION:
switch ($xaction->getNewValue()) {
case DifferentialAction::ACTION_CLAIM:
// When users commandeer revisions, we may need to trigger
// signatures or author-based rules.
return true;
}
break;
}
}

View file

@ -33,7 +33,6 @@ final class DifferentialRevisionPHIDType extends PhabricatorPHIDType {
$revision = $objects[$phid];
$title = $revision->getTitle();
$status = $revision->getStatus();
$monogram = $revision->getMonogram();
$uri = $revision->getURI();
@ -46,10 +45,8 @@ final class DifferentialRevisionPHIDType extends PhabricatorPHIDType {
$handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED);
}
$status = $revision->getStatus();
$icon = $revision->getStatusIcon($status);
$color = $revision->getStatusIconColor($status);
$icon = $revision->getStatusIcon();
$color = $revision->getStatusIconColor();
$name = $revision->getStatusDisplayName();
$handle

View file

@ -10,8 +10,6 @@ final class DifferentialRevisionQuery
private $pathIDs = array();
private $status = 'status-any';
private $authors = array();
private $draftAuthors = array();
private $ccs = array();
@ -25,6 +23,8 @@ final class DifferentialRevisionQuery
private $repositoryPHIDs;
private $updatedEpochMin;
private $updatedEpochMax;
private $statuses;
private $isOpen;
const ORDER_MODIFIED = 'order-modified';
const ORDER_CREATED = 'order-created';
@ -133,16 +133,13 @@ final class DifferentialRevisionQuery
return $this;
}
/**
* Filter results to revisions with a given status. Provide a class constant,
* such as `DifferentialLegacyQuery::STATUS_OPEN`.
*
* @param const Class STATUS constant, like STATUS_OPEN.
* @return this
* @task config
*/
public function withStatus($status_constant) {
$this->status = $status_constant;
public function withStatuses(array $statuses) {
$this->statuses = $statuses;
return $this;
}
public function withIsOpen($is_open) {
$this->isOpen = $is_open;
return $this;
}
@ -694,14 +691,24 @@ final class DifferentialRevisionQuery
$this->updatedEpochMax);
}
// NOTE: Although the status constants are integers in PHP, the column is a
// string column in MySQL, and MySQL won't use keys on string columns if
// you put integers in the query.
$statuses = DifferentialLegacyQuery::getQueryValues($this->status);
if ($statuses !== null) {
if ($this->statuses !== null) {
$where[] = qsprintf(
$conn_r,
'r.status IN (%Ls)',
'r.status in (%Ls)',
$this->statuses);
}
if ($this->isOpen !== null) {
if ($this->isOpen) {
$statuses = DifferentialLegacyQuery::getModernValues(
DifferentialLegacyQuery::STATUS_OPEN);
} else {
$statuses = DifferentialLegacyQuery::getModernValues(
DifferentialLegacyQuery::STATUS_CLOSED);
}
$where[] = qsprintf(
$conn_r,
'r.status in (%Ls)',
$statuses);
}

View file

@ -151,9 +151,8 @@ final class DifferentialRevisionRequiredActionResultBucket
private function filterShouldUpdate(array $phids) {
$statuses = array(
ArcanistDifferentialRevisionStatus::NEEDS_REVISION,
ArcanistDifferentialRevisionStatus::CHANGES_PLANNED,
ArcanistDifferentialRevisionStatus::IN_PREPARATION,
DifferentialRevisionStatus::NEEDS_REVISION,
DifferentialRevisionStatus::CHANGES_PLANNED,
);
$statuses = array_fuse($statuses);
@ -161,7 +160,7 @@ final class DifferentialRevisionRequiredActionResultBucket
$results = array();
foreach ($objects as $key => $object) {
if (empty($statuses[$object->getStatus()])) {
if (empty($statuses[$object->getModernRevisionStatus()])) {
continue;
}
@ -190,10 +189,9 @@ final class DifferentialRevisionRequiredActionResultBucket
private function filterWaitingOnAuthors(array $phids) {
$statuses = array(
ArcanistDifferentialRevisionStatus::ACCEPTED,
ArcanistDifferentialRevisionStatus::NEEDS_REVISION,
ArcanistDifferentialRevisionStatus::CHANGES_PLANNED,
ArcanistDifferentialRevisionStatus::IN_PREPARATION,
DifferentialRevisionStatus::ACCEPTED,
DifferentialRevisionStatus::NEEDS_REVISION,
DifferentialRevisionStatus::CHANGES_PLANNED,
);
$statuses = array_fuse($statuses);
@ -201,7 +199,7 @@ final class DifferentialRevisionRequiredActionResultBucket
$results = array();
foreach ($objects as $key => $object) {
if (empty($statuses[$object->getStatus()])) {
if (empty($statuses[$object->getModernRevisionStatus()])) {
continue;
}

View file

@ -41,8 +41,8 @@ final class DifferentialRevisionSearchEngine
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
}
if ($map['status']) {
$query->withStatus($map['status']);
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
return $query;
@ -77,10 +77,11 @@ final class DifferentialRevisionSearchEngine
->setDatasource(new DiffusionRepositoryFunctionDatasource())
->setDescription(
pht('Find revisions from specific repositories.')),
id(new PhabricatorSearchSelectField())
->setLabel(pht('Status'))
->setKey('status')
->setOptions($this->getStatusOptions())
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Statuses'))
->setKey('statuses')
->setAliases(array('status'))
->setDatasource(new DifferentialRevisionStatusFunctionDatasource())
->setDescription(
pht('Find revisions with particular statuses.')),
);
@ -115,7 +116,7 @@ final class DifferentialRevisionSearchEngine
return $query
->setParameter('responsiblePHIDs', array($viewer->getPHID()))
->setParameter('status', DifferentialLegacyQuery::STATUS_OPEN)
->setParameter('statuses', array('open()'))
->setParameter('bucket', $bucket_key);
case 'authored':
return $query
@ -267,7 +268,7 @@ final class DifferentialRevisionSearchEngine
$blocking_revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withPHIDs($revision_phids)
->withStatus(DifferentialLegacyQuery::STATUS_OPEN)
->withIsOpen(true)
->execute();
$blocking_revisions = mpull($blocking_revisions, null, 'getPHID');

View file

@ -72,7 +72,7 @@ final class DifferentialRevision extends DifferentialDAO
->attachRepository(null)
->attachActiveDiff(null)
->attachReviewers(array())
->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
->setModernRevisionStatus(DifferentialRevisionStatus::NEEDS_REVIEW);
}
protected function getConfiguration() {
@ -612,6 +612,18 @@ final class DifferentialRevision extends DifferentialDAO
return $this;
}
public function setModernRevisionStatus($status) {
return $this->setStatus($status);
}
public function getModernRevisionStatus() {
return $this->getStatus();
}
public function getLegacyRevisionStatus() {
return $this->getStatusObject()->getLegacyKey();
}
public function isClosed() {
return $this->getStatusObject()->isClosedStatus();
}
@ -628,6 +640,10 @@ final class DifferentialRevision extends DifferentialDAO
return $this->getStatusObject()->isNeedsReview();
}
public function isNeedsRevision() {
return $this->getStatusObject()->isNeedsRevision();
}
public function isChangePlanned() {
return $this->getStatusObject()->isChangePlanned();
}
@ -650,7 +666,7 @@ final class DifferentialRevision extends DifferentialDAO
public function getStatusObject() {
$status = $this->getStatus();
return DifferentialRevisionStatus::newForLegacyStatus($status);
return DifferentialRevisionStatus::newForStatus($status);
}
public function getFlag(PhabricatorUser $viewer) {
@ -897,13 +913,26 @@ final class DifferentialRevision extends DifferentialDAO
->setKey('authorPHID')
->setType('phid')
->setDescription(pht('Revision author PHID.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('status')
->setType('map<string, wild>')
->setDescription(pht('Information about revision status.')),
);
}
public function getFieldValuesForConduit() {
$status = $this->getStatusObject();
$status_info = array(
'value' => $status->getKey(),
'name' => $status->getDisplayName(),
'closed' => $status->isClosedStatus(),
'color.ansi' => $status->getANSIColor(),
);
return array(
'title' => $this->getTitle(),
'authorPHID' => $this->getAuthorPHID(),
'status' => $status_info,
);
}

View file

@ -8,7 +8,6 @@ final class DifferentialTransaction
const TYPE_INLINE = 'differential:inline';
const TYPE_UPDATE = 'differential:update';
const TYPE_ACTION = 'differential:action';
const TYPE_STATUS = 'differential:status';
const MAILTAG_REVIEWERS = 'differential-reviewers';
const MAILTAG_CLOSED = 'differential-committed';
@ -305,15 +304,6 @@ final class DifferentialTransaction
return DifferentialAction::getBasicStoryText($new, $author_handle);
}
break;
case self::TYPE_STATUS:
switch ($this->getNewValue()) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
return pht('This revision is now accepted and ready to land.');
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
return pht('This revision now requires changes to proceed.');
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
return pht('This revision now requires review to proceed.');
}
}
return parent::getTitle();
@ -457,21 +447,6 @@ final class DifferentialTransaction
$object_link);
}
break;
case self::TYPE_STATUS:
switch ($this->getNewValue()) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
return pht(
'%s is now accepted and ready to land.',
$object_link);
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
return pht(
'%s now requires changes to proceed.',
$object_link);
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
return pht(
'%s now requires review to proceed.',
$object_link);
}
}
return parent::getTitleForFeed();
@ -483,16 +458,6 @@ final class DifferentialTransaction
return 'fa-comment';
case self::TYPE_UPDATE:
return 'fa-refresh';
case self::TYPE_STATUS:
switch ($this->getNewValue()) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
return 'fa-check';
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
return 'fa-times';
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
return 'fa-undo';
}
break;
case self::TYPE_ACTION:
switch ($this->getNewValue()) {
case DifferentialAction::ACTION_CLOSE:
@ -530,14 +495,12 @@ final class DifferentialTransaction
// Never group status changes with other types of actions, they're indirect
// and don't make sense when combined with direct actions.
$type_status = self::TYPE_STATUS;
if ($this->getTransactionType() == $type_status) {
if ($this->isStatusTransaction($this)) {
return false;
}
foreach ($group as $xaction) {
if ($xaction->getTransactionType() == $type_status) {
if ($this->isStatusTransaction($xaction)) {
return false;
}
}
@ -545,21 +508,20 @@ final class DifferentialTransaction
return parent::shouldDisplayGroupWith($group);
}
private function isStatusTransaction($xaction) {
$status_type = DifferentialRevisionStatusTransaction::TRANSACTIONTYPE;
if ($xaction->getTransactionType() == $status_type) {
return true;
}
return false;
}
public function getColor() {
switch ($this->getTransactionType()) {
case self::TYPE_UPDATE:
return PhabricatorTransactions::COLOR_SKY;
case self::TYPE_STATUS:
switch ($this->getNewValue()) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
return PhabricatorTransactions::COLOR_GREEN;
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
return PhabricatorTransactions::COLOR_RED;
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
return PhabricatorTransactions::COLOR_ORANGE;
}
break;
case self::TYPE_ACTION:
switch ($this->getNewValue()) {
case DifferentialAction::ACTION_CLOSE:

View file

@ -0,0 +1,74 @@
<?php
final class DifferentialRevisionClosedStatusDatasource
extends PhabricatorTypeaheadDatasource {
const FUNCTION_TOKEN = 'closed()';
public function getBrowseTitle() {
return pht('Browse Any Closed Status');
}
public function getPlaceholderText() {
return pht('Type closed()...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
public function getDatasourceFunctions() {
return array(
'closed' => array(
'name' => pht('Any Closed Status'),
'summary' => pht('Find results with any closed status.'),
'description' => pht(
'This function includes results which have any closed status.'),
),
);
}
public function loadResults() {
$results = array(
$this->buildClosedResult(),
);
return $this->filterResultsAgainstTokens($results);
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
$map = DifferentialRevisionStatus::getAll();
foreach ($argv_list as $argv) {
foreach ($map as $status) {
if ($status->isClosedStatus()) {
$results[] = $status->getKey();
}
}
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->buildClosedResult());
}
return $results;
}
private function buildClosedResult() {
$name = pht('Any Closed Status');
return $this->newFunctionResult()
->setName($name.' closed')
->setDisplayName($name)
->setPHID(self::FUNCTION_TOKEN)
->setUnique(true)
->addAttribute(pht('Select any closed status.'));
}
}

View file

@ -0,0 +1,74 @@
<?php
final class DifferentialRevisionOpenStatusDatasource
extends PhabricatorTypeaheadDatasource {
const FUNCTION_TOKEN = 'open()';
public function getBrowseTitle() {
return pht('Browse Any Open Status');
}
public function getPlaceholderText() {
return pht('Type open()...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
public function getDatasourceFunctions() {
return array(
'open' => array(
'name' => pht('Any Open Status'),
'summary' => pht('Find results with any open status.'),
'description' => pht(
'This function includes results which have any open status.'),
),
);
}
public function loadResults() {
$results = array(
$this->buildOpenResult(),
);
return $this->filterResultsAgainstTokens($results);
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
$map = DifferentialRevisionStatus::getAll();
foreach ($argv_list as $argv) {
foreach ($map as $status) {
if (!$status->isClosedStatus()) {
$results[] = $status->getKey();
}
}
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->buildOpenResult());
}
return $results;
}
private function buildOpenResult() {
$name = pht('Any Open Status');
return $this->newFunctionResult()
->setName($name.' open')
->setDisplayName($name)
->setPHID(self::FUNCTION_TOKEN)
->setUnique(true)
->addAttribute(pht('Select any open status.'));
}
}

View file

@ -0,0 +1,52 @@
<?php
final class DifferentialRevisionStatusDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Browse Statuses');
}
public function getPlaceholderText() {
return pht('Type a revision status name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
public function loadResults() {
$results = $this->buildResults();
return $this->filterResultsAgainstTokens($results);
}
protected function renderSpecialTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
private function buildResults() {
$results = array();
$statuses = DifferentialRevisionStatus::getAll();
foreach ($statuses as $status) {
$key = $status->getKey();
$result = id(new PhabricatorTypeaheadResult())
->setIcon($status->getIcon())
->setPHID($key)
->setName($status->getDisplayName());
if ($status->isClosedStatus()) {
$result->addAttribute(pht('Closed Status'));
} else {
$result->addAttribute(pht('Open Status'));
}
$results[$key] = $result;
}
return $results;
}
}

View file

@ -0,0 +1,22 @@
<?php
final class DifferentialRevisionStatusFunctionDatasource
extends PhabricatorTypeaheadCompositeDatasource {
public function getBrowseTitle() {
return pht('Browse Statuses');
}
public function getPlaceholderText() {
return pht('Type a revision status name or function...');
}
public function getComponentDatasources() {
return array(
new DifferentialRevisionStatusDatasource(),
new DifferentialRevisionClosedStatusDatasource(),
new DifferentialRevisionOpenStatusDatasource(),
);
}
}

View file

@ -47,7 +47,8 @@ final class DifferentialRevisionAbandonTransaction
}
public function applyInternalEffects($object, $value) {
$object->setStatus(ArcanistDifferentialRevisionStatus::ABANDONED);
$status_abandoned = DifferentialRevisionStatus::ABANDONED;
$object->setModernRevisionStatus($status_abandoned);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -103,7 +103,7 @@ final class DifferentialRevisionAcceptTransaction
if ($reviewer->isAccepted($diff_phid)) {
// If a reviewer is already in a full "accepted" state, don't
// include that reviewer as an option unless we're listing all
// reviwers, including reviewers who have already accepted.
// reviewers, including reviewers who have already accepted.
continue;
}
}

View file

@ -35,14 +35,10 @@ final class DifferentialRevisionCloseTransaction
}
public function applyInternalEffects($object, $value) {
$status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
$was_accepted = $object->isAccepted();
$old_status = $object->getStatus();
$object->setStatus($status_closed);
$was_accepted = ($old_status == $status_accepted);
$status_published = DifferentialRevisionStatus::PUBLISHED;
$object->setModernRevisionStatus($status_published);
$object->setProperty(
DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED,
@ -50,6 +46,12 @@ final class DifferentialRevisionCloseTransaction
}
protected function validateAction($object, PhabricatorUser $viewer) {
if ($this->getEditor()->getIsCloseByCommit()) {
// If we're closing a revision because we discovered a commit, we don't
// care what state it was in.
return;
}
if ($object->isClosed()) {
throw new Exception(
pht(
@ -78,11 +80,52 @@ final class DifferentialRevisionCloseTransaction
}
public function getTitle() {
if (!$this->getMetadataValue('isCommitClose')) {
return pht(
'%s closed this revision.',
$this->renderAuthor());
}
$commit_phid = $this->getMetadataValue('commitPHID');
$committer_phid = $this->getMetadataValue('committerPHID');
$author_phid = $this->getMetadataValue('authorPHID');
if ($committer_phid) {
$committer_name = $this->renderHandle($committer_phid);
} else {
$committer_name = $this->getMetadataValue('committerName');
}
if ($author_phid) {
$author_name = $this->renderHandle($author_phid);
} else {
$author_name = $this->getMetadatavalue('authorName');
}
$same_phid =
strlen($committer_phid) &&
strlen($author_phid) &&
($committer_phid == $author_phid);
$same_name =
!strlen($committer_phid) &&
!strlen($author_phid) &&
($committer_name == $author_name);
if ($same_name || $same_phid) {
return pht(
'Closed by commit %s (authored by %s).',
$this->renderHandle($commit_phid),
$author_name);
} else {
return pht(
'Closed by commit %s (authored by %s, committed by %s).',
$this->renderHandle($commit_phid),
$author_name,
$committer_name);
}
}
public function getTitleForFeed() {
return pht(
'%s closed %s.',

View file

@ -46,13 +46,12 @@ final class DifferentialRevisionPlanChangesTransaction
}
public function generateOldValue($object) {
$status_planned = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED;
return ($object->getStatus() == $status_planned);
return $object->isChangePlanned();
}
public function applyInternalEffects($object, $value) {
$status_planned = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED;
$object->setStatus($status_planned);
$status_planned = DifferentialRevisionStatus::CHANGES_PLANNED;
$object->setModernRevisionStatus($status_planned);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -47,7 +47,8 @@ final class DifferentialRevisionReclaimTransaction
}
public function applyInternalEffects($object, $value) {
$object->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
$status_review = DifferentialRevisionStatus::NEEDS_REVIEW;
$object->setModernRevisionStatus($status_review);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -35,7 +35,8 @@ final class DifferentialRevisionReopenTransaction
}
public function applyInternalEffects($object, $value) {
$object->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
$status_review = DifferentialRevisionStatus::NEEDS_REVIEW;
$object->setModernRevisionStatus($status_review);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -27,13 +27,12 @@ final class DifferentialRevisionRequestReviewTransaction
}
public function generateOldValue($object) {
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
return ($object->getStatus() == $status_review);
return $object->isNeedsReview();
}
public function applyInternalEffects($object, $value) {
$status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
$object->setStatus($status_review);
$status_review = DifferentialRevisionStatus::NEEDS_REVIEW;
$object->setModernRevisionStatus($status_review);
}
protected function validateAction($object, PhabricatorUser $viewer) {

View file

@ -210,34 +210,6 @@ abstract class DifferentialRevisionReviewTransaction
$map = array_select_keys($map, $value);
}
// Convert reviewer statuses into edge data.
foreach ($map as $reviewer_phid => $reviewer_status) {
$map[$reviewer_phid] = array(
'data' => array(
'status' => $reviewer_status,
),
);
}
// This is currently double-writing: to the old (edge) store and the new
// (reviewer) store. Do the old edge write first.
$src_phid = $revision->getPHID();
$edge_type = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
$editor = new PhabricatorEdgeEditor();
foreach ($map as $dst_phid => $edge_data) {
if ($status == DifferentialReviewerStatus::STATUS_RESIGNED) {
// TODO: For now, we just remove these reviewers. In the future, we will
// store resignations explicitly.
$editor->removeEdge($src_phid, $edge_type, $dst_phid);
} else {
$editor->addEdge($src_phid, $edge_type, $dst_phid, $edge_data);
}
}
$editor->save();
// Now, do the new write.
if ($map) {
@ -249,6 +221,7 @@ abstract class DifferentialRevisionReviewTransaction
}
$table = new DifferentialReviewer();
$src_phid = $revision->getPHID();
$reviewers = $table->loadAllWhere(
'revisionPHID = %s AND reviewerPHID IN (%Ls)',
@ -256,7 +229,7 @@ abstract class DifferentialRevisionReviewTransaction
array_keys($map));
$reviewers = mpull($reviewers, null, 'getReviewerPHID');
foreach ($map as $dst_phid => $edge_data) {
foreach (array_keys($map) as $dst_phid) {
$reviewer = idx($reviewers, $dst_phid);
if (!$reviewer) {
$reviewer = id(new DifferentialReviewer())

View file

@ -106,43 +106,9 @@ final class DifferentialRevisionReviewersTransaction
public function applyExternalEffects($object, $value) {
$src_phid = $object->getPHID();
// This is currently double-writing: to the old (edge) store and the new
// (reviewer) store. Do the old edge write first.
$old = $this->generateOldValue($object);
$new = $value;
$edge_type = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
$editor = new PhabricatorEdgeEditor();
$rem = array_diff_key($old, $new);
foreach ($rem as $dst_phid => $status) {
$editor->removeEdge($src_phid, $edge_type, $dst_phid);
}
foreach ($new as $dst_phid => $status) {
$old_status = idx($old, $dst_phid);
if ($old_status === $status) {
continue;
}
$data = array(
'data' => array(
'status' => $status,
// TODO: This seemes like it's buggy before the Modular Transactions
// changes. Figure out what's going on here? We don't have a very
// clean way to get the active diff ID right now.
'diffID' => null,
),
);
$editor->addEdge($src_phid, $edge_type, $dst_phid, $data);
}
$editor->save();
// Now, do the new write.
$table = new DifferentialReviewer();
$table_name = $table->getTableName();

View file

@ -0,0 +1,73 @@
<?php
final class DifferentialRevisionStatusTransaction
extends DifferentialRevisionTransactionType {
const TRANSACTIONTYPE = 'differential.revision.status';
public function generateOldValue($object) {
return $object->getModernRevisionStatus();
}
public function applyInternalEffects($object, $value) {
$object->setModernRevisionStatus($value);
}
public function getTitle() {
$status = $this->newStatusObject();
if ($status->isAccepted()) {
return pht('This revision is now accepted and ready to land.');
}
if ($status->isNeedsRevision()) {
return pht('This revision now requires changes to proceed.');
}
if ($status->isNeedsReview()) {
return pht('This revision now requires review to proceed.');
}
return null;
}
public function getTitleForFeed() {
$status = $this->newStatusObject();
if ($status->isAccepted()) {
return pht(
'%s is now accepted and ready to land.',
$this->renderObject());
}
if ($status->isNeedsRevision()) {
return pht(
'%s now requires changes to proceed.',
$this->renderObject());
}
if ($status->isNeedsReview()) {
return pht(
'%s now requires review to proceed.',
$this->renderObject());
}
return null;
}
public function getIcon() {
$status = $this->newStatusObject();
return $status->getTimelineIcon();
}
public function getColor() {
$status = $this->newStatusObject();
return $status->getTimelineColor();
}
private function newStatusObject() {
$new = $this->getNewValue();
return DifferentialRevisionStatus::newForStatus($new);
}
}

View file

@ -71,6 +71,11 @@ final class DiffusionBranchTableController extends DiffusionController {
->setHeader(pht('Branches'))
->setHeaderIcon('fa-code-fork');
if (!$repository->isSVN()) {
$branch_tag = $this->renderBranchTag($drequest);
$header->addTag($branch_tag);
}
$tabs = $this->buildTabsView('branch');
$view = id(new PHUITwoColumnView())

View file

@ -5,6 +5,7 @@ final class DiffusionBrowseController extends DiffusionController {
private $lintCommit;
private $lintMessages;
private $coverage;
private $corpusButtons = array();
public function shouldAllowPublic() {
return true;
@ -22,8 +23,7 @@ final class DiffusionBrowseController extends DiffusionController {
// list.
$grep = $request->getStr('grep');
$find = $request->getStr('find');
if (strlen($grep) || strlen($find)) {
if (strlen($grep)) {
return $this->browseSearch();
}
@ -57,14 +57,17 @@ final class DiffusionBrowseController extends DiffusionController {
private function browseSearch() {
$drequest = $this->getDiffusionRequest();
$header = $this->buildHeaderView($drequest);
$path = nonempty(basename($drequest->getPath()), '/');
$search_form = $this->renderSearchForm();
$search_results = $this->renderSearchResults();
$search_form = $this->renderSearchForm($path);
$search_form = id(new PHUIObjectBoxView())
->setHeaderText(pht('Search'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($search_form);
$search_form = phutil_tag(
'div',
array(
'class' => 'diffusion-mobile-search-form',
),
$search_form);
$crumbs = $this->buildCrumbs(
array(
@ -74,8 +77,11 @@ final class DiffusionBrowseController extends DiffusionController {
));
$crumbs->setBorder(true);
$tabs = $this->buildTabsView('code');
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setTabs($tabs)
->setFooter(
array(
$search_form,
@ -235,50 +241,47 @@ final class DiffusionBrowseController extends DiffusionController {
require_celerity_resource('diffusion-source-css');
// Render the page.
$curtain = $this->buildCurtain($drequest, $show_blame, $show_editor);
$properties = $this->buildPropertyView($drequest);
$bar = $this->buildButtonBar($drequest, $show_blame, $show_editor);
$header = $this->buildHeaderView($drequest);
$header->setHeaderIcon('fa-file-code-o');
$content = array();
$follow = $request->getStr('follow');
$follow_notice = null;
if ($follow) {
$notice = new PHUIInfoView();
$notice->setSeverity(PHUIInfoView::SEVERITY_WARNING);
$notice->setTitle(pht('Unable to Continue'));
$follow_notice = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setTitle(pht('Unable to Continue'));
switch ($follow) {
case 'first':
$notice->appendChild(
$follow_notice->appendChild(
pht(
'Unable to continue tracing the history of this file because '.
'this commit is the first commit in the repository.'));
break;
case 'created':
$notice->appendChild(
$follow_notice->appendChild(
pht(
'Unable to continue tracing the history of this file because '.
'this commit created the file.'));
break;
}
$content[] = $notice;
}
$renamed = $request->getStr('renamed');
$renamed_notice = null;
if ($renamed) {
$notice = new PHUIInfoView();
$notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
$notice->setTitle(pht('File Renamed'));
$notice->appendChild(
$renamed_notice = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->setTitle(pht('File Renamed'))
->appendChild(
pht(
'File history passes through a rename from "%s" to "%s".',
$drequest->getPath(),
$renamed));
$content[] = $notice;
}
$content[] = $corpus;
$content[] = $this->buildOpenRevisions();
$open_revisions = $this->buildOpenRevisions();
$owners_list = $this->buildOwnersList($drequest);
$crumbs = $this->buildCrumbs(
array(
@ -289,18 +292,21 @@ final class DiffusionBrowseController extends DiffusionController {
$crumbs->setBorder(true);
$basename = basename($this->getDiffusionRequest()->getPath());
$tabs = $this->buildTabsView('code');
$bar->setRight($this->corpusButtons);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$content,
->setTabs($tabs)
->setFooter(array(
$bar,
$follow_notice,
$renamed_notice,
$corpus,
$open_revisions,
$owners_list,
));
if ($properties) {
$view->addPropertySection(pht('Details'), $properties);
}
$title = array($basename, $repository->getDisplayName());
return $this->newPage()
@ -323,14 +329,12 @@ final class DiffusionBrowseController extends DiffusionController {
$reason = $results->getReasonForEmptyResultSet();
$actions = $this->getActions($drequest);
$this->buildActionButtons($drequest, true);
$details = $this->buildPropertyView($drequest);
$header = $this->buildHeaderView($drequest);
$header->setHeaderIcon('fa-folder-open');
$search_form = $this->renderSearchForm();
$empty_result = null;
$browse_panel = null;
$branch_panel = null;
@ -361,7 +365,7 @@ final class DiffusionBrowseController extends DiffusionController {
$title = nonempty(basename($drequest->getPath()), '/');
$icon = 'fa-folder-open';
$browse_header = $this->buildPanelHeaderView($title, $icon, $actions);
$browse_header = $this->buildPanelHeaderView($title, $icon);
$browse_panel = id(new PHUIObjectBoxView())
->setHeader($browse_header)
@ -369,12 +373,6 @@ final class DiffusionBrowseController extends DiffusionController {
->setTable($browse_table)
->setPager($pager);
$browse_panel->setShowHide(
array(pht('Show Search')),
pht('Hide Search'),
$search_form,
'#');
$path = $drequest->getPath();
$is_branch = (!strlen($path) && $repository->supportsBranchComparison());
if ($is_branch) {
@ -393,15 +391,23 @@ final class DiffusionBrowseController extends DiffusionController {
));
$crumbs->setBorder(true);
$tabs = $this->buildTabsView('code');
$owners_list = $this->buildOwnersList($drequest);
$bar = id(new PHUILeftRightView())
->setRight($this->corpusButtons)
->addClass('diffusion-action-bar');
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setTabs($tabs)
->setFooter(
array(
$bar,
$branch_panel,
$empty_result,
$browse_panel,
$open_revisions,
$owners_list,
$readme,
));
@ -449,159 +455,58 @@ final class DiffusionBrowseController extends DiffusionController {
'limit' => $pager->getPageSize() + 1,
'offset' => $pager->getOffset(),
));
} else { // Filename search.
$search_mode = 'find';
$query_string = $request->getStr('find');
$results = $this->callConduitWithDiffusionRequest(
'diffusion.querypaths',
array(
'pattern' => $query_string,
'commit' => $drequest->getStableCommit(),
'path' => $drequest->getPath(),
'limit' => $pager->getPageSize() + 1,
'offset' => $pager->getOffset(),
));
}
break;
}
$results = $pager->sliceResults($results);
$table = null;
$header = null;
if ($search_mode == 'grep') {
$table = $this->renderGrepResults($results, $query_string);
$header = pht(
$title = pht(
'File content matching "%s" under "%s"',
$query_string,
nonempty($drequest->getPath(), '/'));
} else {
$table = $this->renderFindResults($results);
$header = pht(
'Paths matching "%s" under "%s"',
$query_string,
nonempty($drequest->getPath(), '/'));
$header = id(new PHUIHeaderView())
->setHeader($title)
->addClass('diffusion-search-result-header');
}
return id(new PHUIObjectBoxView())
->setHeaderText($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table)
->setPager($pager);
return array($header, $table, $pager);
}
private function renderGrepResults(array $results, $pattern) {
$drequest = $this->getDiffusionRequest();
require_celerity_resource('phabricator-search-results-css');
$rows = array();
foreach ($results as $result) {
list($path, $line, $string) = $result;
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $path,
'line' => $line,
));
$matches = null;
$count = @preg_match_all(
'('.$pattern.')u',
$string,
$matches,
PREG_OFFSET_CAPTURE);
if (!$count) {
$output = ltrim($string);
} else {
$output = array();
$cursor = 0;
$length = strlen($string);
foreach ($matches[0] as $match) {
$offset = $match[1];
if ($cursor != $offset) {
$output[] = array(
'text' => substr($string, $cursor, $offset),
'highlight' => false,
);
}
$output[] = array(
'text' => $match[0],
'highlight' => true,
);
$cursor = $offset + strlen($match[0]);
}
if ($cursor != $length) {
$output[] = array(
'text' => substr($string, $cursor),
'highlight' => false,
);
}
if ($output) {
$output[0]['text'] = ltrim($output[0]['text']);
}
foreach ($output as $key => $segment) {
if ($segment['highlight']) {
$output[$key] = phutil_tag('strong', array(), $segment['text']);
} else {
$output[$key] = $segment['text'];
}
}
}
$string = phutil_tag(
'pre',
array('class' => 'PhabricatorMonospaced phui-source-fragment'),
$output);
$path = Filesystem::readablePath($path, $drequest->getPath());
$rows[] = array(
phutil_tag('a', array('href' => $href), $path),
$line,
$string,
);
}
$table = id(new AphrontTableView($rows))
->setClassName('remarkup-code')
->setHeaders(array(pht('Path'), pht('Line'), pht('String')))
->setColumnClasses(array('', 'n', 'wide'))
->setNoDataString(
if (!$results) {
return id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NODATA)
->appendChild(
pht(
'The pattern you searched for was not found in the content of any '.
'files.'));
return $table;
}
private function renderFindResults(array $results) {
$drequest = $this->getDiffusionRequest();
$rows = array();
foreach ($results as $result) {
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $result,
));
$readable = Filesystem::readablePath($result, $drequest->getPath());
$rows[] = array(
phutil_tag('a', array('href' => $href), $readable),
);
$grouped = array();
foreach ($results as $file) {
list($path, $line, $string) = $file;
$grouped[$path][] = array($line, $string);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(pht('Path')))
->setColumnClasses(array('wide'))
->setNoDataString(
pht(
'The pattern you searched for did not match the names of any '.
'files.'));
$view = array();
foreach ($grouped as $path => $matches) {
$view[] = id(new DiffusionPatternSearchView())
->setPath($path)
->setMatches($matches)
->setPattern($pattern)
->setDiffusionRequest($drequest)
->render();
}
return $table;
return $view;
}
private function loadLintMessages() {
@ -737,14 +642,13 @@ final class DiffusionBrowseController extends DiffusionController {
Javelin::initBehavior('load-blame', array('id' => $id));
$file = $this->renderFileButton();
$this->corpusButtons[] = $this->renderFileButton();
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-file-code-o';
$drequest = $this->getDiffusionRequest();
$actions = $this->getActions($drequest);
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon, $actions);
$header->addActionLink($file);
$header = $this->buildPanelHeaderView($title, $icon);
$corpus = id(new PHUIObjectBoxView())
->setHeader($header)
@ -783,12 +687,11 @@ final class DiffusionBrowseController extends DiffusionController {
return $corpus;
}
private function buildCurtain(
private function buildButtonBar(
DiffusionRequest $drequest,
$show_blame,
$show_editor) {
$curtain = $this->newCurtainView($drequest);
$viewer = $this->getViewer();
$base_uri = $this->getRequest()->getRequestURI();
@ -796,19 +699,21 @@ final class DiffusionBrowseController extends DiffusionController {
$repository = $drequest->getRepository();
$path = $drequest->getPath();
$line = nonempty((int)$drequest->getLine(), 1);
$buttons = array();
$editor_link = $user->loadEditorLink($path, $line, $repository);
$template = $user->loadEditorLink($path, '%l', $repository);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Show Last Change'))
$buttons[] =
id(new PHUIButtonView())
->setText(pht('Last Change'))
->setColor(PHUIButtonView::GREY)
->setHref(
$drequest->generateURI(
array(
'action' => 'change',
)))
->setIcon('fa-backward'));
->setIcon('fa-backward');
if ($show_blame) {
$blame_text = pht('Disable Blame');
@ -820,48 +725,76 @@ final class DiffusionBrowseController extends DiffusionController {
$blame_value = 1;
}
$curtain->addAction(
id(new PhabricatorActionView())
->setName($blame_text)
->setHref($base_uri->alter('blame', $blame_value))
$blame = id(new PHUIButtonView())
->setText($blame_text)
->setIcon($blame_icon)
->setUser($viewer)
->setRenderAsForm($viewer->isLoggedIn()));
->setColor(PHUIButtonView::GREY);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Open in Editor'))
if ($viewer->isLoggedIn()) {
$blame = phabricator_form(
$viewer,
array(
'action' => $base_uri->alter('blame', $blame_value),
'method' => 'POST',
'style' => 'display: inline-block;',
),
$blame);
} else {
$blame->setTag('a');
$blame->setHref($base_uri->alter('blame', $blame_value));
}
$buttons[] = $blame;
if ($editor_link) {
$buttons[] =
id(new PHUIButtonView())
->setTag('a')
->setText(pht('Open File'))
->setHref($editor_link)
->setIcon('fa-pencil')
->setID('editor_link')
->setMetadata(array('link_template' => $template))
->setDisabled(!$editor_link));
->setDisabled(!$editor_link)
->setColor(PHUIButtonView::GREY);
}
$href = null;
$show_lint = true;
if ($this->getRequest()->getStr('lint') !== null) {
$lint_text = pht('Hide %d Lint Message(s)', count($this->lintMessages));
$lint_text = pht('Hide Lint');
$href = $base_uri->alter('lint', null);
} else if ($this->lintCommit === null) {
$lint_text = pht('Lint not Available');
$show_lint = false;
} else {
$lint_text = pht(
'Show %d Lint Message(s)',
count($this->lintMessages));
$lint_text = pht('Show Lint');
$href = $this->getDiffusionRequest()->generateURI(array(
'action' => 'browse',
'commit' => $this->lintCommit,
))->alter('lint', '');
}
$curtain->addAction(
id(new PhabricatorActionView())
->setName($lint_text)
if ($show_lint) {
$buttons[] =
id(new PHUIButtonView())
->setTag('a')
->setText($lint_text)
->setHref($href)
->setIcon('fa-exclamation-triangle')
->setDisabled(!$href));
->setDisabled(!$href)
->setColor(PHUIButtonView::GREY);
}
$bar = id(new PHUILeftRightView())
->setLeft($buttons)
->addClass('diffusion-action-bar full-mobile-buttons');
return $bar;
}
private function buildOwnersList(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$repository = $drequest->getRepository();
$owners = 'PhabricatorOwnersApplication';
@ -881,30 +814,54 @@ final class DiffusionBrowseController extends DiffusionController {
$repository->getPHID(),
$drequest->getPath());
$ownership = id(new PHUIObjectItemListView())
->setUser($viewer)
->setNoDataString(pht('No Owners'));
if ($packages) {
$ownership = id(new PHUIStatusListView())
->setUser($viewer);
foreach ($packages as $package) {
$icon = 'fa-list-alt';
$color = 'grey';
$item = id(new PHUIObjectItemView())
->setObject($package)
->setObjectName($package->getMonogram())
->setHeader($package->getName())
->setHref($package->getURI());
$item = id(new PHUIStatusItemView())
->setIcon($icon, $color)
->setTarget($viewer->renderHandle($package->getPHID()));
$owners = $package->getOwners();
if ($owners) {
$owner_list = $viewer->renderHandleList(
mpull($owners, 'getUserPHID'));
} else {
$owner_list = phutil_tag('em', array(), pht('None'));
}
$item->addAttribute(pht('Owners: %s', $owner_list));
$auto = $package->getAutoReview();
$autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
$spec = idx($autoreview_map, $auto, array());
$name = idx($spec, 'name', $auto);
$item->addIcon('fa-code', $name);
if ($package->getAuditingEnabled()) {
$item->addIcon('fa-check', pht('Auditing Enabled'));
} else {
$item->addIcon('fa-ban', pht('No Auditing'));
}
if ($package->isArchived()) {
$item->setDisabled(true);
}
$ownership->addItem($item);
}
} else {
$ownership = phutil_tag('em', array(), pht('None'));
}
$curtain->newPanel()
->setHeaderText(pht('Owners'))
->appendChild($ownership);
$view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Owner Packages'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($ownership);
}
return $curtain;
return $view;
}
private function renderFileButton($file_uri = null, $label = null) {
@ -912,11 +869,11 @@ final class DiffusionBrowseController extends DiffusionController {
$base_uri = $this->getRequest()->getRequestURI();
if ($file_uri) {
$text = pht('Download Raw');
$text = pht('Download File');
$href = $file_uri;
$icon = 'fa-download';
} else {
$text = pht('View Raw');
$text = pht('Raw File');
$href = $base_uri->alter('view', 'raw');
$icon = 'fa-file-text';
}
@ -929,7 +886,8 @@ final class DiffusionBrowseController extends DiffusionController {
->setTag('a')
->setText($text)
->setHref($href)
->setIcon($icon);
->setIcon($icon)
->setColor(PHUIButtonView::GREY);
return $button;
}
@ -1358,13 +1316,12 @@ final class DiffusionBrowseController extends DiffusionController {
'src' => $file_uri,
)));
$file = $this->renderFileButton($file_uri);
$this->corpusButtons[] = $this->renderFileButton($file_uri);
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-file-image-o';
$drequest = $this->getDiffusionRequest();
$actions = $this->getActions($drequest);
$header = $this->buildPanelHeaderView($title, $icon, $actions);
$header->addActionLink($file);
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon);
return id(new PHUIObjectBoxView())
->setHeader($header)
@ -1379,13 +1336,12 @@ final class DiffusionBrowseController extends DiffusionController {
->addPadding(PHUI::PADDING_LARGE)
->appendChild($text);
$file = $this->renderFileButton($file_uri);
$this->corpusButtons[] = $this->renderFileButton($file_uri);
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-file';
$drequest = $this->getDiffusionRequest();
$actions = $this->getActions($drequest);
$header = $this->buildPanelHeaderView($title, $icon, $actions);
$header->addActionLink($file);
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon);
$box = id(new PHUIObjectBoxView())
->setHeader($header)
@ -1581,43 +1537,6 @@ final class DiffusionBrowseController extends DiffusionController {
return "{$summary}\n{$date} \xC2\xB7 {$author}";
}
protected function renderSearchForm() {
$drequest = $this->getDiffusionRequest();
$forms = array();
$form = id(new AphrontFormView())
->setUser($this->getViewer())
->setMethod('GET');
switch ($drequest->getRepository()->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$forms[] = id(clone $form)
->appendChild(pht('Search is not available in Subversion.'));
break;
default:
$forms[] = id(clone $form)
->appendChild(
id(new AphrontFormTextWithSubmitControl())
->setLabel(pht('File Name'))
->setSubmitLabel(pht('Search File Names'))
->setName('find')
->setValue($this->getRequest()->getStr('find')));
$forms[] = id(clone $form)
->appendChild(
id(new AphrontFormTextWithSubmitControl())
->setLabel(pht('Pattern'))
->setSubmitLabel(pht('Grep File Content'))
->setName('grep')
->setValue($this->getRequest()->getStr('grep')));
break;
}
require_celerity_resource('diffusion-icons-css');
$form_box = phutil_tag_div('diffusion-search-boxen', $forms);
return $form_box;
}
protected function markupText($text) {
$engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine();
$engine->setConfig('viewer', $this->getRequest()->getUser());
@ -1635,34 +1554,43 @@ final class DiffusionBrowseController extends DiffusionController {
protected function buildHeaderView(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$repository = $drequest->getRepository();
$tag = $this->renderCommitHashTag($drequest);
$commit_tag = $this->renderCommitHashTag($drequest);
$path = nonempty(basename($drequest->getPath()), '/');
$search = $this->renderSearchForm($path);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($this->renderPathLinks($drequest, $mode = 'browse'))
->addTag($tag);
->addActionItem($search)
->addTag($commit_tag)
->addClass('diffusion-browse-header');
if (!$repository->isSVN()) {
$branch_tag = $this->renderBranchTag($drequest);
$header->addTag($branch_tag);
}
return $header;
}
protected function buildPanelHeaderView($title, $icon, array $actions) {
protected function buildPanelHeaderView($title, $icon) {
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon($icon)
->addClass('diffusion-panel-header-view');
foreach ($actions as $action_link) {
if ($action_link) {
$header->addActionLink($action_link);
}
}
return $header;
}
protected function getActions(DiffusionRequest $drequest) {
protected function buildActionButtons(
DiffusionRequest $drequest,
$is_directory = false) {
$viewer = $this->getViewer();
$repository = $drequest->getRepository();
$history_uri = $drequest->generateURI(array('action' => 'history'));
@ -1674,7 +1602,7 @@ final class DiffusionBrowseController extends DiffusionController {
'action' => 'browse',
));
if ($repository->supportsBranchComparison()) {
if ($repository->supportsBranchComparison() && $is_directory) {
$compare_uri = $drequest->generateURI(array('action' => 'compare'));
$compare = id(new PHUIButtonView())
->setText(pht('Compare'))
@ -1683,6 +1611,7 @@ final class DiffusionBrowseController extends DiffusionController {
->setTag('a')
->setHref($compare_uri)
->setColor(PHUIButtonView::GREY);
$this->corpusButtons[] = $compare;
}
$head = null;
@ -1692,6 +1621,7 @@ final class DiffusionBrowseController extends DiffusionController {
->setHref($head_uri)
->setIcon('fa-home')
->setColor(PHUIButtonView::GREY);
$this->corpusButtons[] = $head;
}
$history = id(new PHUIButtonView())
@ -1700,8 +1630,8 @@ final class DiffusionBrowseController extends DiffusionController {
->setTag('a')
->setIcon('fa-history')
->setColor(PHUIButtonView::GREY);
$this->corpusButtons[] = $history;
return array($history, $compare, $head);
}
protected function buildPropertyView(
@ -1758,7 +1688,7 @@ final class DiffusionBrowseController extends DiffusionController {
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withPath($repository->getID(), $path_id)
->withStatus(DifferentialLegacyQuery::STATUS_OPEN)
->withIsOpen(true)
->withUpdatedEpochBetween($recent, null)
->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED)
->setLimit(10)
@ -1905,8 +1835,8 @@ final class DiffusionBrowseController extends DiffusionController {
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-archive';
$drequest = $this->getDiffusionRequest();
$actions = $this->getActions($drequest);
$header = $this->buildPanelHeaderView($title, $icon, $actions);
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon);
$severity = PHUIInfoView::SEVERITY_NOTICE;
@ -1918,14 +1848,13 @@ final class DiffusionBrowseController extends DiffusionController {
try {
$file = $this->loadGitLFSFile($ref);
$data = $this->renderGitLFSButton();
$header->addActionLink($data);
} catch (Exception $ex) {
$severity = PHUIInfoView::SEVERITY_ERROR;
$messages[] = pht('The data for this file could not be loaded.');
}
$raw = $this->renderFileButton(null, pht('View Raw LFS Pointer'));
$header->addActionLink($raw);
$this->corpusButtons[] = $this->renderFileButton(
null, pht('View Raw LFS Pointer'));
$corpus = id(new PHUIObjectBoxView())
->setHeader($header)

View file

@ -148,7 +148,7 @@ abstract class DiffusionController extends PhabricatorController {
if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) {
$branch_name = $drequest->getBranch();
if ($branch_name) {
if (strlen($branch_name)) {
$repository_name .= ' ('.$branch_name.')';
}
}
@ -343,6 +343,38 @@ abstract class DiffusionController extends PhabricatorController {
return $tag;
}
protected function renderBranchTag(DiffusionRequest $drequest) {
$branch = $drequest->getBranch();
$branch = id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(24)
->truncateString($branch);
$tag = id(new PHUITagView())
->setName($branch)
->setColor(PHUITagView::COLOR_INDIGO)
->setBorder(PHUITagView::BORDER_NONE)
->setType(PHUITagView::TYPE_OUTLINE)
->addClass('diffusion-header-branch-tag');
return $tag;
}
protected function renderSymbolicCommit(DiffusionRequest $drequest) {
$symbolic_tag = $drequest->getSymbolicCommit();
$symbolic_tag = id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(24)
->truncateString($symbolic_tag);
$tag = id(new PHUITagView())
->setName($symbolic_tag)
->setIcon('fa-tag')
->setColor(PHUITagView::COLOR_INDIGO)
->setBorder(PHUITagView::BORDER_NONE)
->setType(PHUITagView::TYPE_SHADE);
return $tag;
}
protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) {
$readme_path = $browse->getReadmePath();
if ($readme_path === null) {
@ -410,6 +442,58 @@ abstract class DiffusionController extends PhabricatorController {
->setContent($readme_corpus);
}
protected function renderSearchForm($path = '/') {
$drequest = $this->getDiffusionRequest();
$viewer = $this->getViewer();
switch ($drequest->getRepository()->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
return null;
}
$search_term = $this->getRequest()->getStr('grep');
require_celerity_resource('diffusion-icons-css');
require_celerity_resource('diffusion-css');
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $path,
));
$bar = javelin_tag(
'input',
array(
'type' => 'text',
'id' => 'diffusion-search-input',
'name' => 'grep',
'class' => 'diffusion-search-input',
'sigil' => 'diffusion-search-input',
'placeholder' => pht('Pattern Search'),
'value' => $search_term,
));
$form = phabricator_form(
$viewer,
array(
'method' => 'GET',
'action' => $href,
'sigil' => 'diffusion-search-form',
'class' => 'diffusion-search-form',
'id' => 'diffusion-search-form',
),
array(
$bar,
));
$form_view = phutil_tag(
'div',
array(
'class' => 'diffusion-search-form-view',
),
$form);
return $form_view;
}
protected function buildTabsView($key) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
@ -418,15 +502,15 @@ abstract class DiffusionController extends PhabricatorController {
$view->addMenuItem(
id(new PHUIListItemView())
->setKey('home')
->setName(pht('Home'))
->setIcon('fa-home')
->setKey('code')
->setName(pht('Code'))
->setIcon('fa-code')
->setHref($drequest->generateURI(
array(
'action' => 'branch',
'path' => '/',
)))
->setSelected($key == 'home'));
->setSelected($key == 'code'));
if (!$repository->isSVN()) {
$view->addMenuItem(

View file

@ -11,6 +11,7 @@ final class DiffusionGraphController extends DiffusionController {
if ($response) {
return $response;
}
require_celerity_resource('diffusion-css');
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
@ -83,6 +84,7 @@ final class DiffusionGraphController extends DiffusionController {
private function buildHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$repository = $drequest->getRepository();
$no_path = !strlen($drequest->getPath());
if ($no_path) {
@ -96,6 +98,11 @@ final class DiffusionGraphController extends DiffusionController {
->setHeader($header_text)
->setHeaderIcon('fa-code-fork');
if (!$repository->isSVN()) {
$branch_tag = $this->renderBranchTag($drequest);
$header->addTag($branch_tag);
}
return $header;
}

View file

@ -11,6 +11,7 @@ final class DiffusionHistoryController extends DiffusionController {
if ($response) {
return $response;
}
require_celerity_resource('diffusion-css');
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
@ -78,6 +79,7 @@ final class DiffusionHistoryController extends DiffusionController {
private function buildHeader(DiffusionRequest $drequest) {
$viewer = $this->getViewer();
$repository = $drequest->getRepository();
$no_path = !strlen($drequest->getPath());
if ($no_path) {
@ -91,6 +93,16 @@ final class DiffusionHistoryController extends DiffusionController {
->setHeader($header_text)
->setHeaderIcon('fa-clock-o');
if (!$repository->isSVN()) {
$branch_tag = $this->renderBranchTag($drequest);
$header->addTag($branch_tag);
}
if ($drequest->getSymbolicCommit()) {
$symbolic_tag = $this->renderSymbolicCommit($drequest);
$header->addTag($symbolic_tag);
}
return $header;
}

View file

@ -167,6 +167,7 @@ final class DiffusionLintController extends DiffusionController {
'path' => true,
'view' => 'lint',
));
$crumbs->setBorder(true);
if ($drequest) {
$title[] = $drequest->getRepository()->getDisplayName();
@ -178,7 +179,7 @@ final class DiffusionLintController extends DiffusionController {
$branch = $drequest->loadBranch();
$header = id(new PHUIHeaderView())
->setHeader($this->renderPathLinks($drequest, 'lint'))
->setHeader(pht('Lint: %s', $this->renderPathLinks($drequest, 'lint')))
->setUser($viewer)
->setHeaderIcon('fa-code');
$actions = $this->buildActionView($drequest);
@ -465,6 +466,7 @@ final class DiffusionLintController extends DiffusionController {
'path' => true,
'view' => 'lint',
));
$crumbs->setBorder(true);
$header = id(new PHUIHeaderView())
->setHeader(pht('Lint: %s', $drequest->getRepository()->getDisplayName()))

View file

@ -31,8 +31,6 @@ final class DiffusionRepositoryController extends DiffusionController {
$description = $this->buildDescriptionView($repository);
$locate_file = $this->buildLocateFile();
$header->setActionList($actions);
// Before we do any work, make sure we're looking at a some content: we're
// on a valid branch, and the repository is not empty.
$page_has_content = false;
@ -100,7 +98,7 @@ final class DiffusionRepositoryController extends DiffusionController {
->setErrors(array($empty_message));
}
$tabs = $this->buildTabsView('home');
$tabs = $this->buildTabsView('code');
$clone_uri = $drequest->generateURI(
array(
@ -113,6 +111,15 @@ final class DiffusionRepositoryController extends DiffusionController {
$clone_text = pht('Clone');
}
$actions_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Actions'))
->setIcon('fa-bars')
->addClass('mmr')
->setColor(PHUIButtonView::GREY)
->setDropdown(true)
->setDropdownMenu($actions);
$clone_button = id(new PHUIButtonView())
->setTag('a')
->setText($clone_text)
@ -123,7 +130,7 @@ final class DiffusionRepositoryController extends DiffusionController {
$bar = id(new PHUILeftRightView())
->setLeft($locate_file)
->setRight(array($this->branchButton, $clone_button))
->setRight(array($this->branchButton, $actions_button, $clone_button))
->addClass('diffusion-action-bar');
$view = id(new PHUITwoColumnView())
@ -293,6 +300,9 @@ final class DiffusionRepositoryController extends DiffusionController {
private function buildHeaderView(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$search = $this->renderSearchForm();
$header = id(new PHUIHeaderView())
->setHeader($repository->getName())
->setUser($viewer)
@ -300,6 +310,7 @@ final class DiffusionRepositoryController extends DiffusionController {
->setProfileHeader(true)
->setImage($repository->getProfileImageURI())
->setImageEditURL('/diffusion/picture/'.$repository->getID().'/')
->addActionItem($search)
->addClass('diffusion-profile-header');
if (!$repository->isTracked()) {
@ -315,6 +326,14 @@ final class DiffusionRepositoryController extends DiffusionController {
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
}
if (!$repository->isSVN()) {
$default = $repository->getDefaultBranch();
if ($default != $drequest->getBranch()) {
$branch_tag = $this->renderBranchTag($drequest);
$header->addTag($branch_tag);
}
}
return $header;
}
@ -546,8 +565,22 @@ final class DiffusionRepositoryController extends DiffusionController {
$browse_uri = $drequest->generateURI(array('action' => 'browse'));
$pager->setURI($browse_uri, 'offset');
$repository_name = $repository->getName();
$branch_name = $drequest->getBranch();
if (strlen($branch_name)) {
$repository_name .= ' ('.$branch_name.')';
}
$header = phutil_tag(
'a',
array(
'href' => $browse_uri,
'class' => 'diffusion-view-browse-header',
),
$repository_name);
return id(new PHUIObjectBoxView())
->setHeaderText($repository->getName())
->setHeaderText($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($browse_table)
->setPager($pager);

View file

@ -37,9 +37,6 @@ final class DiffusionRepositoryEditController
$crumbs->setBorder(true);
$title = pht('Choose Repository Type');
$header = id(new PHUIHeaderView())
->setHeader(pht('Create Repository'))
->setHeaderIcon('fa-plus-square');
$layout = id(new AphrontMultiColumnView())
->setFluidLayout(true);
@ -47,8 +44,10 @@ final class DiffusionRepositoryEditController
$create_uri = $request->getRequestURI();
foreach ($vcs_types as $vcs_key => $vcs_type) {
$image = idx($vcs_type, 'image');
$image = PhabricatorFile::loadBuiltin($viewer, $image);
$action = id(new PHUIActionPanelView())
->setIcon(idx($vcs_type, 'icon'))
->setImage($image->getBestURI())
->setHeader(idx($vcs_type, 'create.header'))
->setHref($create_uri->alter('vcs', $vcs_key))
->setSubheader(idx($vcs_type, 'create.subheader'));
@ -62,9 +61,12 @@ final class DiffusionRepositoryEditController
$observe_href = PhabricatorEnv::getDoclink(
'Diffusion User Guide: Existing Repositories');
require_celerity_resource('diffusion-css');
$image = PhabricatorFile::loadBuiltin($viewer, 'repo/repo.png');
$hints->addColumn(
id(new PHUIActionPanelView())
->setIcon('fa-book')
->setImage($image->getBestURI())
->setHeader(pht('Import or Observe an Existing Repository'))
->setHref($observe_href)
->setSubheader(
@ -72,12 +74,15 @@ final class DiffusionRepositoryEditController
'Review the documentation describing how to import or observe an '.
'existing repository.')));
$layout = id(new PHUIBoxView())
->addClass('diffusion-create-repo')
->appendChild($layout);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFixed(true)
->setFooter(
array(
$layout,
phutil_tag('br'),
$hints,
));

View file

@ -11,6 +11,7 @@ final class DiffusionTagListController extends DiffusionController {
if ($response) {
return $response;
}
require_celerity_resource('diffusion-css');
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
@ -50,6 +51,11 @@ final class DiffusionTagListController extends DiffusionController {
->setHeader(pht('Tags'))
->setHeaderIcon('fa-tags');
if (!$repository->isSVN()) {
$branch_tag = $this->renderBranchTag($drequest);
$header->addTag($branch_tag);
}
if (!$tags) {
$content = $this->renderStatusMessage(
pht('No Tags'),

View file

@ -19,37 +19,16 @@ final class DiffusionCommitRevisionAcceptedHeraldField
return null;
}
$status = $revision->getStatus();
switch ($status) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
if ($revision->isAccepted()) {
return $revision->getPHID();
case ArcanistDifferentialRevisionStatus::CLOSED:
if ($revision->hasRevisionProperty(
DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED)) {
if ($revision->getProperty(
DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED)) {
return $revision->getPHID();
} else {
return null;
}
} else {
// continue on to old-style precommitRevisionStatus
break;
}
default:
return null;
}
$data = $object->getCommitData();
$status = $data->getCommitDetail('precommitRevisionStatus');
switch ($status) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
case ArcanistDifferentialRevisionStatus::CLOSED:
$was_accepted = DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED;
if ($revision->isPublished()) {
if ($revision->getProperty($was_accepted)) {
return $revision->getPHID();
}
}
return null;
}

View file

@ -15,21 +15,19 @@ final class DiffusionPreCommitContentRevisionAcceptedHeraldField
public function getHeraldFieldValue($object) {
$revision = $this->getAdapter()->getRevision();
if (!$revision) {
return null;
}
switch ($revision->getStatus()) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
return $revision->getPHID();
case ArcanistDifferentialRevisionStatus::CLOSED:
if ($revision->getProperty(
DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED)) {
if ($revision->isAccepted()) {
return $revision->getPHID();
}
$was_accepted = DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED;
if ($revision->isPublished()) {
if ($revision->getProperty($was_accepted)) {
return $revision->getPHID();
}
break;
}
return null;

View file

@ -110,6 +110,7 @@ final class DiffusionRepositoryBranchesManagementPanel
->execute();
$branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches);
$branches = $pager->sliceResults($branches);
$can_close_branches = ($repository->isHg());
$rows = array();
foreach ($branches as $branch) {
@ -117,8 +118,25 @@ final class DiffusionRepositoryBranchesManagementPanel
$tracking = $repository->shouldTrackBranch($branch_name);
$autoclosing = $repository->shouldAutocloseBranch($branch_name);
$default = $repository->getDefaultBranch();
$icon = null;
if ($default == $branch->getShortName()) {
$icon = id(new PHUIIconView())
->setIcon('fa-code-fork');
}
$fields = $branch->getRawFields();
$closed = idx($fields, 'closed');
if ($closed) {
$status = pht('Closed');
} else {
$status = pht('Open');
}
$rows[] = array(
$icon,
$branch_name,
$status,
$tracking ? pht('Tracking') : pht('Off'),
$autoclosing ? pht('Autoclose On') : pht('Off'),
);
@ -126,16 +144,28 @@ final class DiffusionRepositoryBranchesManagementPanel
$branch_table = new AphrontTableView($rows);
$branch_table->setHeaders(
array(
'',
pht('Branch'),
pht('Status'),
pht('Track'),
pht('Autoclose'),
));
$branch_table->setColumnClasses(
array(
'',
'pri',
'narrow',
'narrow',
'wide',
));
$branch_table->setColumnVisibility(
array(
true,
true,
$can_close_branches,
true,
true,
));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Branch Status'))

View file

@ -233,6 +233,7 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
$object_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form)
->setFormErrors($errors);
@ -258,6 +259,7 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
$remove_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Remove VCS Password'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($remove_form);
$saved = null;

View file

@ -74,14 +74,6 @@ final class DiffusionBranchListView extends DiffusionView {
}
}
$fields = $branch->getRawFields();
$closed = idx($fields, 'closed');
if ($closed) {
$status = pht('Closed');
} else {
$status = pht('Open');
}
$browse_href = $drequest->generateURI(
array(
'action' => 'browse',
@ -129,6 +121,18 @@ final class DiffusionBranchListView extends DiffusionView {
}
$item->addAttribute(array($datetime));
if ($can_close_branches) {
$fields = $branch->getRawFields();
$closed = idx($fields, 'closed');
if ($closed) {
$status = pht('Branch Closed');
$item->setDisabled(true);
} else {
$status = pht('Branch Open');
}
$item->addAttribute($status);
}
$list->addItem($item);
}

View file

@ -0,0 +1,124 @@
<?php
final class DiffusionPatternSearchView extends DiffusionView {
private $path;
private $matches;
private $pattern;
public function setPath($path) {
$this->path = $path;
return $this;
}
public function setMatches(array $matches) {
$this->matches = $matches;
return $this;
}
public function setPattern($pattern) {
$this->pattern = $pattern;
return $this;
}
public function render() {
$drequest = $this->getDiffusionRequest();
$path = $this->path;
$pattern = $this->pattern;
$rows = array();
foreach ($this->matches as $result) {
list($line, $string) = $result;
$matches = null;
$count = @preg_match_all(
'('.$pattern.')u',
$string,
$matches,
PREG_OFFSET_CAPTURE);
if (!$count) {
$output = ltrim($string);
} else {
$output = array();
$cursor = 0;
$length = strlen($string);
foreach ($matches[0] as $match) {
$offset = $match[1];
if ($cursor != $offset) {
$output[] = array(
'text' => substr($string, $cursor, $offset),
'highlight' => false,
);
}
$output[] = array(
'text' => $match[0],
'highlight' => true,
);
$cursor = $offset + strlen($match[0]);
}
if ($cursor != $length) {
$output[] = array(
'text' => substr($string, $cursor),
'highlight' => false,
);
}
if ($output) {
$output[0]['text'] = ltrim($output[0]['text']);
}
foreach ($output as $key => $segment) {
if ($segment['highlight']) {
$output[$key] = phutil_tag('strong', array(), $segment['text']);
} else {
$output[$key] = $segment['text'];
}
}
}
$string = phutil_tag(
'pre',
array('class' => 'PhabricatorMonospaced phui-source-fragment'),
$output);
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $path,
'line' => $line,
));
$rows[] = array(
phutil_tag('a', array('href' => $href), $line),
$string,
);
}
$path_title = Filesystem::readablePath($this->path, $drequest->getPath());
$href = $drequest->generateURI(array(
'action' => 'browse',
'path' => $path_title,
));
$title = phutil_tag('a', array('href' => $href), $path_title);
$table = id(new AphrontTableView($rows))
->setClassName('remarkup-code')
->setHeaders(array(pht('Line'), pht('String')))
->setColumnClasses(array('n', 'wide'));
$header = id(new PHUIHeaderView())
->setHeader($title);
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
return $box->render();
}
}

View file

@ -18,6 +18,25 @@ final class PhamePostViewController
$is_live = $this->getIsLive();
$is_external = $this->getIsExternal();
// Register a blog "view" count
//
if (!$post->isDraft() && !$post->isArchived()) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$xactions = array();
$xactions[] = id(new PhamePostTransaction())
->setTransactionType(PhamePostViewsTransaction::TRANSACTIONTYPE)
->setNewValue(null);
$editor = id(new PhamePostEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true);
$editor->applyTransactions($post, $xactions);
unset($unguarded);
}
$header = id(new PHUIHeaderView())
->addClass('phame-header-bar')
->setUser($viewer);
@ -151,6 +170,11 @@ final class PhamePostViewController
->setUser($viewer)
->setObject($post);
$views = id(new PhutilNumber($post->getViews()));
$properties->addProperty(
pht('Views'),
pht('%s', $views));
$is_live = $this->getIsLive();
$is_external = $this->getIsExternal();
$next_view = new PhameNextPostView();

View file

@ -41,6 +41,12 @@ final class PhamePostEditor
if ($object->isDraft() || $object->isArchived()) {
return false;
}
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case PhamePostViewsTransaction::TRANSACTIONTYPE:
return false;
}
}
return true;
}

View file

@ -22,6 +22,7 @@ final class PhamePost extends PhameDAO
protected $phameTitle;
protected $body;
protected $visibility;
protected $views;
protected $configData;
protected $datePublished;
protected $blogPHID;
@ -40,7 +41,8 @@ final class PhamePost extends PhameDAO
->setBlogPHID($blog->getPHID())
->attachBlog($blog)
->setDatePublished(PhabricatorTime::getNow())
->setVisibility(PhameConstants::VISIBILITY_PUBLISHED);
->setVisibility(PhameConstants::VISIBILITY_PUBLISHED)
->setViews(0);
return $post;
}
@ -128,6 +130,7 @@ final class PhamePost extends PhameDAO
'subtitle' => 'text64',
'phameTitle' => 'sort64?',
'visibility' => 'uint32',
'views' => 'uint32',
'mailKey' => 'bytes20',
'headerImagePHID' => 'phid?',

View file

@ -0,0 +1,18 @@
<?php
final class PhamePostViewsTransaction
extends PhamePostTransactionType {
const TRANSACTIONTYPE = 'phame.post.views';
public function generateOldValue($object) {
return $object->getViews();
}
public function applyInternalEffects($object, $value) {
$views = $object->getViews();
$views++;
$object->setViews($views);
}
}

View file

@ -26,18 +26,21 @@ final class PhabricatorRepositoryType extends Phobject {
self::REPOSITORY_TYPE_GIT => array(
'name' => pht('Git'),
'icon' => 'fa-git',
'image' => 'repo/repo-git.png',
'create.header' => pht('Create Git Repository'),
'create.subheader' => pht('Create a new Git repository.'),
),
self::REPOSITORY_TYPE_MERCURIAL => array(
'name' => pht('Mercurial'),
'icon' => 'fa-code-fork',
'image' => 'repo/repo-hg.png',
'create.header' => pht('Create Mercurial Repository'),
'create.subheader' => pht('Create a new Mercurial repository.'),
),
self::REPOSITORY_TYPE_SVN => array(
'name' => pht('Subversion'),
'icon' => 'fa-database',
'image' => 'repo/repo-svn.png',
'create.header' => pht('Create Subversion Repository'),
'create.subheader' => pht('Create a new Subversion repository.'),
),

View file

@ -186,11 +186,6 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
$revision = $revision_query->executeOne();
if ($revision) {
if (!$data->getCommitDetail('precommitRevisionStatus')) {
$data->setCommitDetail(
'precommitRevisionStatus',
$revision->getStatus());
}
$commit_drev = DiffusionCommitHasRevisionEdgeType::EDGECONST;
id(new PhabricatorEdgeEditor())
->addEdge($commit->getPHID(), $commit_drev, $revision->getPHID())
@ -205,9 +200,11 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
$should_close = !$revision->isPublished() && $should_autoclose;
if ($should_close) {
$type_close = DifferentialRevisionCloseTransaction::TRANSACTIONTYPE;
$commit_close_xaction = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
->setNewValue(DifferentialAction::ACTION_CLOSE)
->setTransactionType($type_close)
->setNewValue(true)
->setMetadataValue('isCommitClose', true);
$commit_close_xaction->setMetadataValue(

View file

@ -28,55 +28,46 @@ final class PhabricatorNamedQueryQuery
return $this;
}
protected function loadPage() {
$table = new PhabricatorNamedQuery();
$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);
public function newResultObject() {
return new PhabricatorNamedQuery();
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
if ($this->ids) {
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'id IN (%Ld)',
$this->ids);
}
if ($this->engineClassNames) {
if ($this->engineClassNames !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'engineClassName IN (%Ls)',
$this->engineClassNames);
}
if ($this->userPHIDs) {
if ($this->userPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'userPHID IN (%Ls)',
$this->userPHIDs);
}
if ($this->queryKeys) {
if ($this->queryKeys !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'queryKey IN (%Ls)',
$this->queryKeys);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
return $where;
}
public function getQueryApplicationClass() {

View file

@ -121,18 +121,18 @@ final class PhabricatorSettingsMainController
}
$header = id(new PHUIHeaderView())
->setHeader($header_text)
->setHeaderIcon('fa-pencil');
->setHeader($header_text);
$title = $panel->getPanelName();
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter($response);
->setFixed(true)
->setNavigation($nav)
->setMainColumn($response);
return $this->newPage()
->setTitle($title)
->setNavigation($nav)
->setCrumbs($crumbs)
->appendChild($view);

View file

@ -6,7 +6,7 @@ final class PhabricatorConpherencePreferencesSettingsPanel
const PANELKEY = 'conpherence';
public function getPanelName() {
return pht('Conpherence Preferences');
return pht('Conpherence');
}
public function getPanelGroupKey() {

View file

@ -1141,10 +1141,8 @@ abstract class PhabricatorEditEngine
if ($this->getIsCreate()) {
$header_text = $this->getFormHeaderText($object);
$header_icon = 'fa-plus-square';
} else {
$header_text = $this->getObjectEditTitleText($object);
$header_icon = 'fa-pencil';
}
$show_preview = !$request->isAjax();
@ -1185,8 +1183,7 @@ abstract class PhabricatorEditEngine
$crumbs = $this->buildCrumbs($object, $final = true);
$header = id(new PHUIHeaderView())
->setHeader($header_text)
->setHeaderIcon($header_icon);
->setHeader($header_text);
$crumbs->setBorder(true);
if ($action_button) {
@ -1216,8 +1213,6 @@ abstract class PhabricatorEditEngine
$view->setHeader($header);
}
$view->setFooter($content);
$page = $controller->newPage()
->setTitle($header_text)
->setCrumbs($crumbs)
@ -1225,7 +1220,11 @@ abstract class PhabricatorEditEngine
$navigation = $this->getNavigation();
if ($navigation) {
$page->setNavigation($navigation);
$view->setFixed(true);
$view->setNavigation($navigation);
$view->setMainColumn($content);
} else {
$view->setFooter($content);
}
return $page;

View file

@ -140,7 +140,7 @@ Reproducibility
The most important part of your report content is instructions on how to
reproduce the issue. What did you do? If you do it again, does it still break?
Does it depend on a specific browser? Can you reproduce the issue on a free
Does it depend on a specific browser? Can you reproduce the issue on a test
instance on `admin.phabricator.com`?
It is nearly impossible for us to resolve many issues if we can not reproduce

View file

@ -92,8 +92,14 @@ JX.install('AphlictClientServer', {
var server = this._server.listen.apply(this._server, arguments);
var wss = new WebSocket.Server({server: server});
wss.on('connection', function(ws) {
var path = url.parse(ws.upgradeReq.url).pathname;
// This function checks for upgradeReq which is only available in
// ws2 by default, not ws3. See T12755 for more information.
wss.on('connection', function(ws, request) {
if ('upgradeReq' in ws) {
request = ws.upgradeReq;
}
var path = url.parse(request.url).pathname;
var instance = self._parseInstanceFromPath(path);
var listener = self.getListenerList(instance).addListener(ws);

View file

@ -28,6 +28,9 @@ div.jx-typeahead-results a.jx-result {
color: {$darkgreytext};
display: block;
font-size: {$normalfontsize};
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
div.jx-typeahead-results a.jx-result + a.jx-result {
@ -68,7 +71,8 @@ div.jx-typeahead-results a.diffusion-locate-file {
}
.diffusion-locate-file strong {
color: {$blue};
color: {$fire};
text-decoration: underline;
}
.diffusion-locate-file .phui-icon-view {

View file

@ -186,6 +186,7 @@ a.handle-status-closed:hover {
.device .phabricator-standard-page-tabs {
margin-bottom: 20px;
padding: 0 12px;
}
.device-phone .phabricator-standard-page-tabs {

View file

@ -12,6 +12,10 @@
display: block;
}
.device-phone .diffusion-profile-header .phui-header-col1 {
display: none;
}
.diffusion-action-bar {
margin-bottom: 16px;
}
@ -33,6 +37,22 @@
display: block;
}
.device-phone .diffusion-action-bar .button .phui-button-text {
visibility: hidden;
width: 0;
margin-left: 8px;
}
.device-phone .full-mobile-buttons.diffusion-action-bar .phui-lr-container
.phui-left-view {
display: inline-block;
}
.device-phone .full-mobile-buttons.diffusion-action-bar .phui-lr-container
.phui-right-view {
display: inline-block;
}
.diffusion-profile-locate .phui-form-view {
margin: 0;
padding: 0;
@ -60,6 +80,12 @@
padding: 0;
}
.diffusion-view-browse-header {
display: block;
padding: 2px 0;
font-size: {$biggestfontsize};
}
/* - List Styles ------------------------------------------------------------*/
.diffusion-history-list .phui-oi-link {
@ -106,6 +132,12 @@
margin-right: 4px;
}
.diffusion-header-branch-tag.phui-tag-view.phui-tag-type-outline
.phui-tag-core {
padding: 3px 12px 2px;
font-size: {$normalfontsize};
}
/* - Browse Styles ----------------------------------------------------------*/
.diffusion-browse-table .commit-detail {
@ -116,6 +148,58 @@
color: {$darkbluetext};
}
.diffusion-search-result-header.phui-header-shell {
border: none;
padding-bottom: 24px;
}
/* - Search Input ------------------------------------------------------------*/
.diffusion-search-form-view {
width: 240px;
}
.diffusion-search-form-view .diffusion-search-input {
width: 240px;
border-radius: 20px;
padding-left: 12px;
}
.device-phone .diffusion-browse-header .diffusion-search-form-view,
.device-phone .diffusion-profile-header .diffusion-search-form-view {
display: none;
}
.diffusion-mobile-search-form {
display: none;
}
.device-phone .diffusion-mobile-search-form {
display: block;
}
.device-phone .diffusion-search-form-view {
width: 100%;
margin-bottom: 20px;
}
.device-phone .diffusion-search-form-view .diffusion-search-input {
width: 100%;
}
/* - Create Repository -------------------------------------------------------*/
.diffusion-create-repo {
margin-top: 32px;
margin-bottom: 20px;
}
.device .diffusion-create-repo {
margin-top: 0;
margin-bottom: 0;
}
/* - Phone Style ------------------------------------------------------------*/
.device-phone.diffusion-history-view .phui-two-column-view

View file

@ -12,9 +12,10 @@
}
.phui-source-fragment strong {
background-color: {$lightyellow};
font-weight: normal;
background-color: {$gentle.highlight};
font-weight: 600;
color: {$blacktext};
letter-spacing: 0.02em;
}
.phui-fulltext-tokens {

View file

@ -21,6 +21,14 @@
text-align: right;
}
.phui-left-view .button {
margin-right: 8px;
}
.phui-right-view .button {
margin-left: 8px;
}
.phui-lr-view-top .phui-left-view,
.phui-lr-view-top .phui-right-view {
vertical-align: top;

View file

@ -185,6 +185,15 @@
padding: 0 12px;
}
.device-phone .phui-two-column-tabs .phui-list-view.phui-list-tabbar {
text-align: center;
}
.device-phone .phui-two-column-tabs .phui-list-view.phui-list-tabbar > li {
float: none;
display: inline-block;
}
/* Info View */
.phui-two-column-view .phui-info-view {
@ -235,3 +244,54 @@
.phui-document-view {
margin: 0 0 20px 0;
}
/*- Fixed Styles with Navigation -------------------------------------------- */
.phui-two-column-fixed.phui-two-column-view .phui-two-column-header {
background: transparent;
border: none;
margin-bottom: 0;
}
.phui-two-column-fixed.phui-two-column-view .phui-side-column
.phui-box-border {
background: transparent;
border: none;
padding: 0;
width: 180px;
}
.device-desktop
.phui-two-column-fixed.phui-two-column-view.phui-side-column-left
.phui-side-column {
width: 200px;
}
.device-desktop
.phui-two-column-fixed.phui-two-column-view.phui-side-column-left
.phui-main-column {
width: calc(100% - 200px)
}
.phui-two-column-fixed.phui-two-column-view .phui-basic-nav
.phabricator-side-menu {
background: transparent;
}
.phui-two-column-fixed.phui-two-column-view
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected {
border-radius: 3px;
background-color: #f5f9ff;
border: 1px solid {$sky};
padding-left: 3px;
}
.phui-two-column-fixed.phui-two-column-view .phui-basic-nav
.phabricator-side-menu .phui-list-item-href {
border-radius: 3px;
}
.phui-two-column-fixed.phui-two-column-view .phui-header-action-links
.phui-mobile-menu {
display: block;
}

View file

@ -14,7 +14,7 @@ only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-resolution: 1.5dppx) {
.sprite-login {
background-image: url(/rsrc/image/sprite-login-X2.png);
background-size: 145px 174px;
background-size: 145px 145px;
}
}
@ -35,28 +35,24 @@ only screen and (min-resolution: 1.5dppx) {
background-position: -87px 0px;
}
.login-Dropbox {
.login-Facebook {
background-position: -116px 0px;
}
.login-Facebook {
.login-Generic {
background-position: 0px -29px;
}
.login-Generic {
.login-Github {
background-position: -29px -29px;
}
.login-Github {
.login-Google {
background-position: -58px -29px;
}
.login-Google {
background-position: -87px -29px;
}
.login-HTTP {
background-position: -116px -29px;
background-position: -87px -29px;
}
.login-Jira {
@ -67,54 +63,42 @@ only screen and (min-resolution: 1.5dppx) {
background-position: -29px -58px;
}
.login-Linkedin {
.login-MediaWiki {
background-position: -58px -58px;
}
.login-MediaWiki {
.login-PayPal {
background-position: -87px -58px;
}
.login-Openid {
background-position: -116px -58px;
}
.login-PayPal {
.login-Phabricator {
background-position: 0px -87px;
}
.login-Phabricator {
background-position: -58px -87px;
}
.login-Slack {
background-position: -87px -87px;
background-position: -29px -87px;
}
.login-Stripe {
background-position: -116px -87px;
background-position: -58px -87px;
}
.login-TestPayment {
background-position: 0px -116px;
background-position: -87px -87px;
}
.login-TwitchTV {
background-position: -29px -116px;
background-position: 0px -116px;
}
.login-Twitter {
background-position: -58px -116px;
background-position: -29px -116px;
}
.login-WePay {
background-position: -87px -116px;
background-position: -58px -116px;
}
.login-WordPressCOM {
background-position: -116px -116px;
}
.login-Yahoo {
background-position: 0px -145px;
background-position: -87px -116px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 12 KiB