mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-13 15:28:35 +01:00
(stable) Promote 2016 Week 20
This commit is contained in:
commit
90c06115e5
157 changed files with 5396 additions and 5956 deletions
|
@ -7,12 +7,12 @@
|
|||
*/
|
||||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => 'b729f9f5',
|
||||
'core.pkg.css' => 'b7b8d101',
|
||||
'core.pkg.js' => '6972d365',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '7ba78475',
|
||||
'differential.pkg.js' => 'd0cd0df6',
|
||||
'diffusion.pkg.css' => 'dc8e0cc2',
|
||||
'diffusion.pkg.css' => '91c5d3a6',
|
||||
'diffusion.pkg.js' => '3a9a8bfa',
|
||||
'maniphest.pkg.css' => '4845691a',
|
||||
'maniphest.pkg.js' => '949a7498',
|
||||
|
@ -52,7 +52,7 @@ return array(
|
|||
'rsrc/css/application/conpherence/update.css' => 'faf6be09',
|
||||
'rsrc/css/application/conpherence/widget-pane.css' => '775eaaba',
|
||||
'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4',
|
||||
'rsrc/css/application/countdown/timer.css' => '96696f21',
|
||||
'rsrc/css/application/countdown/timer.css' => '16c52f5c',
|
||||
'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a',
|
||||
'rsrc/css/application/dashboard/dashboard.css' => 'bc6f2127',
|
||||
'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a',
|
||||
|
@ -64,7 +64,7 @@ return array(
|
|||
'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
|
||||
'rsrc/css/application/differential/revision-list.css' => 'f3c47d33',
|
||||
'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55',
|
||||
'rsrc/css/application/diffusion/diffusion-icons.css' => '3311444d',
|
||||
'rsrc/css/application/diffusion/diffusion-icons.css' => 'd678600a',
|
||||
'rsrc/css/application/diffusion/diffusion-readme.css' => '297373eb',
|
||||
'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3',
|
||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||
|
@ -104,8 +104,8 @@ return array(
|
|||
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
||||
'rsrc/css/application/uiexample/example.css' => '528b19de',
|
||||
'rsrc/css/core/core.css' => 'd0801452',
|
||||
'rsrc/css/core/remarkup.css' => '6aae5360',
|
||||
'rsrc/css/core/syntax.css' => '9fd11da8',
|
||||
'rsrc/css/core/remarkup.css' => '787105d6',
|
||||
'rsrc/css/core/syntax.css' => '5101175d',
|
||||
'rsrc/css/core/z-index.css' => '5b6fcf3f',
|
||||
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
|
||||
'rsrc/css/font/font-aleo.css' => '8bdb2835',
|
||||
|
@ -113,7 +113,7 @@ return array(
|
|||
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
||||
'rsrc/css/font/phui-font-icon-base.css' => '6449bce8',
|
||||
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
|
||||
'rsrc/css/layout/phabricator-side-menu-view.css' => '3a3d9f41',
|
||||
'rsrc/css/layout/phabricator-side-menu-view.css' => 'dd849797',
|
||||
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338',
|
||||
|
@ -123,15 +123,15 @@ return array(
|
|||
'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
|
||||
'rsrc/css/phui/phui-badge.css' => '3baef8db',
|
||||
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
|
||||
'rsrc/css/phui/phui-box.css' => 'd909ea3d',
|
||||
'rsrc/css/phui/phui-box.css' => '5c8387cf',
|
||||
'rsrc/css/phui/phui-button.css' => 'a64a8de6',
|
||||
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
|
||||
'rsrc/css/phui/phui-crumbs-view.css' => '1a1265d4',
|
||||
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
|
||||
'rsrc/css/phui/phui-document-pro.css' => '73e45fd2',
|
||||
'rsrc/css/phui/phui-document-pro.css' => '8419560b',
|
||||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||
'rsrc/css/phui/phui-document.css' => '9c71d2bf',
|
||||
'rsrc/css/phui/phui-feed-story.css' => 'd8440402',
|
||||
'rsrc/css/phui/phui-document.css' => '715aedfb',
|
||||
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
|
||||
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
|
||||
'rsrc/css/phui/phui-form-view.css' => '6a51768e',
|
||||
'rsrc/css/phui/phui-form.css' => 'aac1d51d',
|
||||
|
@ -153,7 +153,7 @@ return array(
|
|||
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
|
||||
'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
|
||||
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
||||
'rsrc/css/phui/phui-status.css' => '37309046',
|
||||
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
||||
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
|
||||
'rsrc/css/phui/phui-timeline-view.css' => '6e342216',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => 'b9538af1',
|
||||
|
@ -164,6 +164,7 @@ return array(
|
|||
'rsrc/css/sprite-login.css' => '60e8560e',
|
||||
'rsrc/css/sprite-menu.css' => '9dd65b92',
|
||||
'rsrc/css/sprite-tokens.css' => '4f399012',
|
||||
'rsrc/css/syntax/syntax-default.css' => '9923583c',
|
||||
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
|
||||
'rsrc/externals/font/aleo/aleo-bold.eot' => 'd3d3bed7',
|
||||
'rsrc/externals/font/aleo/aleo-bold.svg' => '45899c8e',
|
||||
|
@ -503,6 +504,7 @@ return array(
|
|||
'rsrc/js/core/behavior-reveal-content.js' => '60821bc7',
|
||||
'rsrc/js/core/behavior-scrollbar.js' => '834a1173',
|
||||
'rsrc/js/core/behavior-search-typeahead.js' => '06c32383',
|
||||
'rsrc/js/core/behavior-select-content.js' => 'bf5374ef',
|
||||
'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6',
|
||||
'rsrc/js/core/behavior-time-typeahead.js' => '522431f7',
|
||||
'rsrc/js/core/behavior-toggle-class.js' => '92b9ec77',
|
||||
|
@ -556,7 +558,7 @@ return array(
|
|||
'differential-revision-history-css' => '0e8eb855',
|
||||
'differential-revision-list-css' => 'f3c47d33',
|
||||
'differential-table-of-contents-css' => 'ae4b7a55',
|
||||
'diffusion-icons-css' => '3311444d',
|
||||
'diffusion-icons-css' => 'd678600a',
|
||||
'diffusion-readme-css' => '297373eb',
|
||||
'diffusion-source-css' => '68b30fd3',
|
||||
'diviner-shared-css' => 'aa3656aa',
|
||||
|
@ -684,6 +686,7 @@ return array(
|
|||
'javelin-behavior-repository-crossreference' => 'e5339c43',
|
||||
'javelin-behavior-scrollbar' => '834a1173',
|
||||
'javelin-behavior-search-reorder-queries' => 'e9581f08',
|
||||
'javelin-behavior-select-content' => 'bf5374ef',
|
||||
'javelin-behavior-select-on-click' => '4e3e79a6',
|
||||
'javelin-behavior-slowvote-embed' => '887ad43f',
|
||||
'javelin-behavior-stripe-payment-form' => '3f5d6dbf',
|
||||
|
@ -758,7 +761,7 @@ return array(
|
|||
'phabricator-chatlog-css' => 'd295b020',
|
||||
'phabricator-content-source-view-css' => '4b8b05d4',
|
||||
'phabricator-core-css' => 'd0801452',
|
||||
'phabricator-countdown-css' => '96696f21',
|
||||
'phabricator-countdown-css' => '16c52f5c',
|
||||
'phabricator-dashboard-css' => 'bc6f2127',
|
||||
'phabricator-drag-and-drop-file-upload' => '81f182b5',
|
||||
'phabricator-draggable-list' => '5a13c79f',
|
||||
|
@ -777,10 +780,10 @@ return array(
|
|||
'phabricator-object-selector-css' => '85ee8ce6',
|
||||
'phabricator-phtize' => 'd254d646',
|
||||
'phabricator-prefab' => 'e67df814',
|
||||
'phabricator-remarkup-css' => '6aae5360',
|
||||
'phabricator-remarkup-css' => '787105d6',
|
||||
'phabricator-search-results-css' => '7dea472c',
|
||||
'phabricator-shaped-request' => '7cbe244b',
|
||||
'phabricator-side-menu-view-css' => '3a3d9f41',
|
||||
'phabricator-side-menu-view-css' => 'dd849797',
|
||||
'phabricator-slowvote-css' => 'a94b7230',
|
||||
'phabricator-source-code-view-css' => 'cbeef983',
|
||||
'phabricator-standard-page-view' => 'e709f6d0',
|
||||
|
@ -811,7 +814,7 @@ return array(
|
|||
'phui-action-panel-css' => '91c7b835',
|
||||
'phui-badge-view-css' => '3baef8db',
|
||||
'phui-big-info-view-css' => 'bd903741',
|
||||
'phui-box-css' => 'd909ea3d',
|
||||
'phui-box-css' => '5c8387cf',
|
||||
'phui-button-css' => 'a64a8de6',
|
||||
'phui-calendar-css' => 'ccabe893',
|
||||
'phui-calendar-day-css' => 'd1cf6f93',
|
||||
|
@ -821,9 +824,9 @@ return array(
|
|||
'phui-crumbs-view-css' => '1a1265d4',
|
||||
'phui-curtain-view-css' => '7148ae25',
|
||||
'phui-document-summary-view-css' => '9ca48bdf',
|
||||
'phui-document-view-css' => '9c71d2bf',
|
||||
'phui-document-view-pro-css' => '73e45fd2',
|
||||
'phui-feed-story-css' => 'd8440402',
|
||||
'phui-document-view-css' => '715aedfb',
|
||||
'phui-document-view-pro-css' => '8419560b',
|
||||
'phui-feed-story-css' => 'aa49845d',
|
||||
'phui-font-icon-base-css' => '6449bce8',
|
||||
'phui-fontkit-css' => '9cda225e',
|
||||
'phui-form-css' => 'aac1d51d',
|
||||
|
@ -848,7 +851,7 @@ return array(
|
|||
'phui-remarkup-preview-css' => '1a8f2591',
|
||||
'phui-segment-bar-view-css' => '46342871',
|
||||
'phui-spacing-css' => '042804d6',
|
||||
'phui-status-list-view-css' => '37309046',
|
||||
'phui-status-list-view-css' => 'd5263e49',
|
||||
'phui-tag-view-css' => '6bbd83e2',
|
||||
'phui-theme-css' => '027ba77e',
|
||||
'phui-timeline-view-css' => '6e342216',
|
||||
|
@ -877,7 +880,8 @@ return array(
|
|||
'sprite-login-css' => '60e8560e',
|
||||
'sprite-menu-css' => '9dd65b92',
|
||||
'sprite-tokens-css' => '4f399012',
|
||||
'syntax-highlighting-css' => '9fd11da8',
|
||||
'syntax-default-css' => '9923583c',
|
||||
'syntax-highlighting-css' => '5101175d',
|
||||
'tokens-css' => '3d0f239e',
|
||||
'typeahead-browse-css' => 'd8581d2c',
|
||||
'unhandled-exception-css' => '4c96257a',
|
||||
|
@ -1239,6 +1243,9 @@ return array(
|
|||
'javelin-typeahead-source',
|
||||
'javelin-util',
|
||||
),
|
||||
'5101175d' => array(
|
||||
'syntax-default-css',
|
||||
),
|
||||
'519705ea' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1832,6 +1839,11 @@ return array(
|
|||
'javelin-util',
|
||||
'javelin-request',
|
||||
),
|
||||
'bf5374ef' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
),
|
||||
'bff6884b' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -2192,6 +2204,7 @@ return array(
|
|||
'aphront-list-filter-view-css',
|
||||
'phabricator-remarkup-css',
|
||||
'syntax-highlighting-css',
|
||||
'syntax-default-css',
|
||||
'phui-pager-css',
|
||||
'aphront-tooltip-css',
|
||||
'phabricator-flag-css',
|
||||
|
|
|
@ -97,6 +97,7 @@ return array(
|
|||
|
||||
'phabricator-remarkup-css',
|
||||
'syntax-highlighting-css',
|
||||
'syntax-default-css',
|
||||
'phui-pager-css',
|
||||
'aphront-tooltip-css',
|
||||
'phabricator-flag-css',
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorRepository();
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $repo) {
|
||||
$repo->updateURIIndex();
|
||||
}
|
||||
// A later patch ("20160510.repo.01.uriindex.php") performs an identical
|
||||
// regeneration of the index, so we no longer need to do it here.
|
||||
|
|
2
resources/sql/autopatches/20160503.repo.01.lpath.sql
Normal file
2
resources/sql/autopatches/20160503.repo.01.lpath.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||
ADD localPath VARCHAR(128) COLLATE {$COLLATE_TEXT};
|
2
resources/sql/autopatches/20160503.repo.02.lpathkey.sql
Normal file
2
resources/sql/autopatches/20160503.repo.02.lpathkey.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||
ADD UNIQUE KEY `key_local` (localPath);
|
57
resources/sql/autopatches/20160503.repo.03.lpathmigrate.php
Normal file
57
resources/sql/autopatches/20160503.repo.03.lpathmigrate.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorRepository();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$default_path = PhabricatorEnv::getEnvConfig('repository.default-local-path');
|
||||
$default_path = rtrim($default_path, '/');
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $repository) {
|
||||
$local_path = $repository->getLocalPath();
|
||||
if (strlen($local_path)) {
|
||||
// Repository already has a modern, unique local path.
|
||||
continue;
|
||||
}
|
||||
|
||||
$local_path = $repository->getDetail('local-path');
|
||||
if (!strlen($local_path)) {
|
||||
// Repository does not have a local path using the older format.
|
||||
continue;
|
||||
}
|
||||
|
||||
$random = Filesystem::readRandomCharacters(8);
|
||||
|
||||
// Try the configured path first, then a default path, then a path with some
|
||||
// random noise.
|
||||
$paths = array(
|
||||
$local_path,
|
||||
$default_path.'/'.$repository->getID().'/',
|
||||
$default_path.'/'.$repository->getID().'-'.$random.'/',
|
||||
);
|
||||
|
||||
foreach ($paths as $path) {
|
||||
// Set, then get the path to normalize it.
|
||||
$repository->setLocalPath($path);
|
||||
$path = $repository->getLocalPath();
|
||||
|
||||
try {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET localPath = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
$path,
|
||||
$repository->getID());
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Assigned repository "%s" to local path "%s".',
|
||||
$repository->getDisplayName(),
|
||||
$path));
|
||||
|
||||
break;
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
// Ignore, try the next one.
|
||||
}
|
||||
}
|
||||
}
|
38
resources/sql/autopatches/20160503.repo.04.mirrormigrate.php
Normal file
38
resources/sql/autopatches/20160503.repo.04.mirrormigrate.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorRepository();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$mirrors = queryfx_all(
|
||||
$conn_w,
|
||||
'SELECT * FROM %T',
|
||||
'repository_mirror');
|
||||
|
||||
foreach ($mirrors as $mirror) {
|
||||
$repository_phid = $mirror['repositoryPHID'];
|
||||
$uri = $mirror['remoteURI'];
|
||||
|
||||
$already_exists = id(new PhabricatorRepositoryURI())->loadOneWhere(
|
||||
'repositoryPHID = %s AND uri = %s',
|
||||
$repository_phid,
|
||||
$uri);
|
||||
if ($already_exists) {
|
||||
// Decline to migrate stuff that looks like it was already migrated.
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_uri = PhabricatorRepositoryURI::initializeNewURI()
|
||||
->setIOType(PhabricatorRepositoryURI::IO_MIRROR)
|
||||
->setRepositoryPHID($repository_phid)
|
||||
->setURI($uri)
|
||||
->setCredentialPHID($mirror['credentialPHID'])
|
||||
->setDateCreated($mirror['dateCreated'])
|
||||
->setDateModified($mirror['dateModified'])
|
||||
->save();
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Migrated mirror "%s".',
|
||||
$uri));
|
||||
}
|
82
resources/sql/autopatches/20160503.repo.05.urimigrate.php
Normal file
82
resources/sql/autopatches/20160503.repo.05.urimigrate.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorRepository();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $repository) {
|
||||
$uris = array();
|
||||
|
||||
$serve_http = $repository->getDetail('serve-over-http');
|
||||
$http_io = PhabricatorRepositoryURI::IO_DEFAULT;
|
||||
$disable_http = false;
|
||||
switch ($serve_http) {
|
||||
case 'readwrite':
|
||||
break;
|
||||
case 'readonly':
|
||||
$http_io = PhabricatorRepositoryURI::IO_READ;
|
||||
break;
|
||||
case 'off':
|
||||
default:
|
||||
$disable_http = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$serve_ssh = $repository->getDetail('serve-over-ssh');
|
||||
$ssh_io = PhabricatorRepositoryURI::IO_DEFAULT;
|
||||
$disable_ssh = false;
|
||||
switch ($serve_ssh) {
|
||||
case 'readwrite':
|
||||
break;
|
||||
case 'readonly':
|
||||
$ssh_io = PhabricatorRepositoryURI::IO_READ;
|
||||
break;
|
||||
case 'off':
|
||||
default:
|
||||
$disable_ssh = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$uris = $repository->newBuiltinURIs();
|
||||
|
||||
foreach ($uris as $uri) {
|
||||
$builtin_protocol = $uri->getBuiltinProtocol();
|
||||
if ($builtin_protocol == PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH) {
|
||||
$uri->setIsDisabled((int)$disable_ssh);
|
||||
$uri->setIoType($ssh_io);
|
||||
} else {
|
||||
$uri->setIsDisabled((int)$disable_http);
|
||||
$uri->setIoType($http_io);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$repository->isHosted()) {
|
||||
$remote_uri = $repository->getDetail('remote-uri');
|
||||
if (strlen($remote_uri)) {
|
||||
$uris[] = PhabricatorRepositoryURI::initializeNewURI()
|
||||
->setRepositoryPHID($repository->getPHID())
|
||||
->attachRepository($repository)
|
||||
->setURI($remote_uri)
|
||||
->setCredentialPHID($repository->getCredentialPHID())
|
||||
->setIOType(PhabricatorRepositoryURI::IO_OBSERVE);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($uris as $uri) {
|
||||
$already_exists = id(new PhabricatorRepositoryURI())->loadOneWhere(
|
||||
'repositoryPHID = %s AND uri = %s LIMIT 1',
|
||||
$repository->getPHID(),
|
||||
$uri->getURI());
|
||||
if ($already_exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$uri->save();
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Migrated URI "%s" for repository "%s".',
|
||||
$uri->getURI(),
|
||||
$repository->getDisplayName()));
|
||||
}
|
||||
}
|
10
resources/sql/autopatches/20160510.repo.01.uriindex.php
Normal file
10
resources/sql/autopatches/20160510.repo.01.uriindex.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
$repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->needURIs(true)
|
||||
->execute();
|
||||
|
||||
foreach ($repos as $repo) {
|
||||
$repo->updateURIIndex();
|
||||
}
|
|
@ -226,6 +226,7 @@ phutil_register_library_map(array(
|
|||
'CelerityHighContrastPostprocessor' => 'applications/celerity/postprocessor/CelerityHighContrastPostprocessor.php',
|
||||
'CelerityLargeFontPostprocessor' => 'applications/celerity/postprocessor/CelerityLargeFontPostprocessor.php',
|
||||
'CelerityManagementMapWorkflow' => 'applications/celerity/management/CelerityManagementMapWorkflow.php',
|
||||
'CelerityManagementSyntaxWorkflow' => 'applications/celerity/management/CelerityManagementSyntaxWorkflow.php',
|
||||
'CelerityManagementWorkflow' => 'applications/celerity/management/CelerityManagementWorkflow.php',
|
||||
'CelerityPhabricatorResourceController' => 'applications/celerity/controller/CelerityPhabricatorResourceController.php',
|
||||
'CelerityPhabricatorResources' => 'applications/celerity/resources/CelerityPhabricatorResources.php',
|
||||
|
@ -361,6 +362,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialBlameRevisionField' => 'applications/differential/customfield/DifferentialBlameRevisionField.php',
|
||||
'DifferentialBlockHeraldAction' => 'applications/differential/herald/DifferentialBlockHeraldAction.php',
|
||||
'DifferentialBranchField' => 'applications/differential/customfield/DifferentialBranchField.php',
|
||||
'DifferentialChangeDetailMailView' => 'applications/differential/mail/DifferentialChangeDetailMailView.php',
|
||||
'DifferentialChangeHeraldFieldGroup' => 'applications/differential/herald/DifferentialChangeHeraldFieldGroup.php',
|
||||
'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php',
|
||||
'DifferentialChangesSinceLastUpdateField' => 'applications/differential/customfield/DifferentialChangesSinceLastUpdateField.php',
|
||||
|
@ -369,6 +371,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php',
|
||||
'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php',
|
||||
'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php',
|
||||
'DifferentialChangesetOneUpMailRenderer' => 'applications/differential/render/DifferentialChangesetOneUpMailRenderer.php',
|
||||
'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php',
|
||||
'DifferentialChangesetOneUpTestRenderer' => 'applications/differential/render/DifferentialChangesetOneUpTestRenderer.php',
|
||||
'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php',
|
||||
|
@ -458,6 +461,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialHunkTestCase' => 'applications/differential/storage/__tests__/DifferentialHunkTestCase.php',
|
||||
'DifferentialInlineComment' => 'applications/differential/storage/DifferentialInlineComment.php',
|
||||
'DifferentialInlineCommentEditController' => 'applications/differential/controller/DifferentialInlineCommentEditController.php',
|
||||
'DifferentialInlineCommentMailView' => 'applications/differential/mail/DifferentialInlineCommentMailView.php',
|
||||
'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/DifferentialInlineCommentPreviewController.php',
|
||||
'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php',
|
||||
'DifferentialJIRAIssuesField' => 'applications/differential/customfield/DifferentialJIRAIssuesField.php',
|
||||
|
@ -468,6 +472,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php',
|
||||
'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php',
|
||||
'DifferentialLocalCommitsView' => 'applications/differential/view/DifferentialLocalCommitsView.php',
|
||||
'DifferentialMailView' => 'applications/differential/mail/DifferentialMailView.php',
|
||||
'DifferentialManiphestTasksField' => 'applications/differential/customfield/DifferentialManiphestTasksField.php',
|
||||
'DifferentialModernHunk' => 'applications/differential/storage/DifferentialModernHunk.php',
|
||||
'DifferentialNextStepField' => 'applications/differential/customfield/DifferentialNextStepField.php',
|
||||
|
@ -570,6 +575,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionCachedResolveRefsQuery' => 'applications/diffusion/query/DiffusionCachedResolveRefsQuery.php',
|
||||
'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php',
|
||||
'DiffusionChangeHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionChangeHeraldFieldGroup.php',
|
||||
'DiffusionCloneURIView' => 'applications/diffusion/view/DiffusionCloneURIView.php',
|
||||
'DiffusionCommandEngine' => 'applications/diffusion/protocol/DiffusionCommandEngine.php',
|
||||
'DiffusionCommandEngineTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php',
|
||||
'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php',
|
||||
|
@ -616,6 +622,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php',
|
||||
'DiffusionCreateCommentConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php',
|
||||
'DiffusionCreateRepositoriesCapability' => 'applications/diffusion/capability/DiffusionCreateRepositoriesCapability.php',
|
||||
'DiffusionDaemonLockException' => 'applications/diffusion/exception/DiffusionDaemonLockException.php',
|
||||
'DiffusionDefaultEditCapability' => 'applications/diffusion/capability/DiffusionDefaultEditCapability.php',
|
||||
'DiffusionDefaultPushCapability' => 'applications/diffusion/capability/DiffusionDefaultPushCapability.php',
|
||||
'DiffusionDefaultViewCapability' => 'applications/diffusion/capability/DiffusionDefaultViewCapability.php',
|
||||
|
@ -659,6 +666,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionLintController' => 'applications/diffusion/controller/DiffusionLintController.php',
|
||||
'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php',
|
||||
'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php',
|
||||
'DiffusionLocalRepositoryFilter' => 'applications/diffusion/data/DiffusionLocalRepositoryFilter.php',
|
||||
'DiffusionLookSoonConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php',
|
||||
'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php',
|
||||
'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php',
|
||||
|
@ -682,8 +690,6 @@ phutil_register_library_map(array(
|
|||
'DiffusionMercurialWireProtocolTests' => 'applications/diffusion/protocol/__tests__/DiffusionMercurialWireProtocolTests.php',
|
||||
'DiffusionMercurialWireSSHTestCase' => 'applications/diffusion/ssh/__tests__/DiffusionMercurialWireSSHTestCase.php',
|
||||
'DiffusionMergedCommitsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php',
|
||||
'DiffusionMirrorDeleteController' => 'applications/diffusion/controller/DiffusionMirrorDeleteController.php',
|
||||
'DiffusionMirrorEditController' => 'applications/diffusion/controller/DiffusionMirrorEditController.php',
|
||||
'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php',
|
||||
'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php',
|
||||
'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php',
|
||||
|
@ -751,32 +757,21 @@ phutil_register_library_map(array(
|
|||
'DiffusionRepositoryClusterEngine' => 'applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php',
|
||||
'DiffusionRepositoryClusterEngineLogInterface' => 'applications/diffusion/protocol/DiffusionRepositoryClusterEngineLogInterface.php',
|
||||
'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php',
|
||||
'DiffusionRepositoryCreateController' => 'applications/diffusion/controller/DiffusionRepositoryCreateController.php',
|
||||
'DiffusionRepositoryDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryDatasource.php',
|
||||
'DiffusionRepositoryDefaultController' => 'applications/diffusion/controller/DiffusionRepositoryDefaultController.php',
|
||||
'DiffusionRepositoryEditActionsController' => 'applications/diffusion/controller/DiffusionRepositoryEditActionsController.php',
|
||||
'DiffusionRepositoryDocumentationManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php',
|
||||
'DiffusionRepositoryEditActivateController' => 'applications/diffusion/controller/DiffusionRepositoryEditActivateController.php',
|
||||
'DiffusionRepositoryEditAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php',
|
||||
'DiffusionRepositoryEditBasicController' => 'applications/diffusion/controller/DiffusionRepositoryEditBasicController.php',
|
||||
'DiffusionRepositoryEditBranchesController' => 'applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php',
|
||||
'DiffusionRepositoryEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositoryEditConduitAPIMethod.php',
|
||||
'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php',
|
||||
'DiffusionRepositoryEditDangerousController' => 'applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php',
|
||||
'DiffusionRepositoryEditDeleteController' => 'applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php',
|
||||
'DiffusionRepositoryEditEncodingController' => 'applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php',
|
||||
'DiffusionRepositoryEditEngine' => 'applications/diffusion/editor/DiffusionRepositoryEditEngine.php',
|
||||
'DiffusionRepositoryEditHostingController' => 'applications/diffusion/controller/DiffusionRepositoryEditHostingController.php',
|
||||
'DiffusionRepositoryEditMainController' => 'applications/diffusion/controller/DiffusionRepositoryEditMainController.php',
|
||||
'DiffusionRepositoryEditStagingController' => 'applications/diffusion/controller/DiffusionRepositoryEditStagingController.php',
|
||||
'DiffusionRepositoryEditStorageController' => 'applications/diffusion/controller/DiffusionRepositoryEditStorageController.php',
|
||||
'DiffusionRepositoryEditSubversionController' => 'applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php',
|
||||
'DiffusionRepositoryEditUpdateController' => 'applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php',
|
||||
'DiffusionRepositoryEditproController' => 'applications/diffusion/controller/DiffusionRepositoryEditproController.php',
|
||||
'DiffusionRepositoryHistoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php',
|
||||
'DiffusionRepositoryListController' => 'applications/diffusion/controller/DiffusionRepositoryListController.php',
|
||||
'DiffusionRepositoryManageController' => 'applications/diffusion/controller/DiffusionRepositoryManageController.php',
|
||||
'DiffusionRepositoryManagePanelsController' => 'applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php',
|
||||
'DiffusionRepositoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryManagementPanel.php',
|
||||
'DiffusionRepositoryNewController' => 'applications/diffusion/controller/DiffusionRepositoryNewController.php',
|
||||
'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php',
|
||||
'DiffusionRepositoryPoliciesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php',
|
||||
'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php',
|
||||
|
@ -785,10 +780,11 @@ phutil_register_library_map(array(
|
|||
'DiffusionRepositoryStagingManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php',
|
||||
'DiffusionRepositoryStatusManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php',
|
||||
'DiffusionRepositoryStorageManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php',
|
||||
'DiffusionRepositorySymbolsController' => 'applications/diffusion/controller/DiffusionRepositorySymbolsController.php',
|
||||
'DiffusionRepositorySubversionManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php',
|
||||
'DiffusionRepositorySymbolsManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php',
|
||||
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
|
||||
'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php',
|
||||
'DiffusionRepositoryURICredentialController' => 'applications/diffusion/controller/DiffusionRepositoryURICredentialController.php',
|
||||
'DiffusionRepositoryURIDisableController' => 'applications/diffusion/controller/DiffusionRepositoryURIDisableController.php',
|
||||
'DiffusionRepositoryURIEditController' => 'applications/diffusion/controller/DiffusionRepositoryURIEditController.php',
|
||||
'DiffusionRepositoryURIViewController' => 'applications/diffusion/controller/DiffusionRepositoryURIViewController.php',
|
||||
|
@ -2286,6 +2282,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php',
|
||||
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
|
||||
'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php',
|
||||
'PhabricatorDefaultSyntaxStyle' => 'infrastructure/syntax/PhabricatorDefaultSyntaxStyle.php',
|
||||
'PhabricatorDesktopNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php',
|
||||
'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php',
|
||||
'PhabricatorDestructionEngine' => 'applications/system/engine/PhabricatorDestructionEngine.php',
|
||||
|
@ -2357,6 +2354,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEditEngineSelectCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineSelectCommentAction.php',
|
||||
'PhabricatorEditEngineTokenizerCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineTokenizerCommentAction.php',
|
||||
'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php',
|
||||
'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php',
|
||||
'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php',
|
||||
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
|
||||
'PhabricatorElasticFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php',
|
||||
|
@ -3188,7 +3186,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
|
||||
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php',
|
||||
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
|
||||
'PhabricatorRepositoryManagementEditWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php',
|
||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
|
||||
'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php',
|
||||
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
|
||||
|
@ -3207,8 +3204,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryMercurialCommitMessageParserWorker.php',
|
||||
'PhabricatorRepositoryMirror' => 'applications/repository/storage/PhabricatorRepositoryMirror.php',
|
||||
'PhabricatorRepositoryMirrorEngine' => 'applications/repository/engine/PhabricatorRepositoryMirrorEngine.php',
|
||||
'PhabricatorRepositoryMirrorPHIDType' => 'applications/repository/phid/PhabricatorRepositoryMirrorPHIDType.php',
|
||||
'PhabricatorRepositoryMirrorQuery' => 'applications/repository/query/PhabricatorRepositoryMirrorQuery.php',
|
||||
'PhabricatorRepositoryParsedChange' => 'applications/repository/data/PhabricatorRepositoryParsedChange.php',
|
||||
'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php',
|
||||
'PhabricatorRepositoryPullEvent' => 'applications/repository/storage/PhabricatorRepositoryPullEvent.php',
|
||||
|
@ -3469,6 +3464,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSupportApplication' => 'applications/support/application/PhabricatorSupportApplication.php',
|
||||
'PhabricatorSyntaxHighlighter' => 'infrastructure/markup/PhabricatorSyntaxHighlighter.php',
|
||||
'PhabricatorSyntaxHighlightingConfigOptions' => 'applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php',
|
||||
'PhabricatorSyntaxStyle' => 'infrastructure/syntax/PhabricatorSyntaxStyle.php',
|
||||
'PhabricatorSystemAction' => 'applications/system/action/PhabricatorSystemAction.php',
|
||||
'PhabricatorSystemActionEngine' => 'applications/system/engine/PhabricatorSystemActionEngine.php',
|
||||
'PhabricatorSystemActionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemActionGarbageCollector.php',
|
||||
|
@ -4103,7 +4099,6 @@ phutil_register_library_map(array(
|
|||
'ReleephWorkRecordPickStatusConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php',
|
||||
'RemarkupProcessConduitAPIMethod' => 'applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php',
|
||||
'RepositoryConduitAPIMethod' => 'applications/repository/conduit/RepositoryConduitAPIMethod.php',
|
||||
'RepositoryCreateConduitAPIMethod' => 'applications/repository/conduit/RepositoryCreateConduitAPIMethod.php',
|
||||
'RepositoryQueryConduitAPIMethod' => 'applications/repository/conduit/RepositoryQueryConduitAPIMethod.php',
|
||||
'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php',
|
||||
'SlowvoteConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteConduitAPIMethod.php',
|
||||
|
@ -4413,6 +4408,7 @@ phutil_register_library_map(array(
|
|||
'CelerityHighContrastPostprocessor' => 'CelerityPostprocessor',
|
||||
'CelerityLargeFontPostprocessor' => 'CelerityPostprocessor',
|
||||
'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow',
|
||||
'CelerityManagementSyntaxWorkflow' => 'CelerityManagementWorkflow',
|
||||
'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'CelerityPhabricatorResourceController' => 'CelerityResourceController',
|
||||
'CelerityPhabricatorResources' => 'CelerityResourcesOnDisk',
|
||||
|
@ -4446,7 +4442,7 @@ phutil_register_library_map(array(
|
|||
'ConduitCallTestCase' => 'PhabricatorTestCase',
|
||||
'ConduitColumnsParameterType' => 'ConduitParameterType',
|
||||
'ConduitConnectConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'ConduitEpochParameterType' => 'ConduitListParameterType',
|
||||
'ConduitEpochParameterType' => 'ConduitParameterType',
|
||||
'ConduitException' => 'Exception',
|
||||
'ConduitGetCapabilitiesConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'ConduitGetCertificateConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
|
@ -4470,7 +4466,7 @@ phutil_register_library_map(array(
|
|||
'ConduitTokenGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
'ConduitUserListParameterType' => 'ConduitListParameterType',
|
||||
'ConduitUserParameterType' => 'ConduitParameterType',
|
||||
'ConduitWildParameterType' => 'ConduitListParameterType',
|
||||
'ConduitWildParameterType' => 'ConduitParameterType',
|
||||
'ConpherenceColumnViewController' => 'ConpherenceController',
|
||||
'ConpherenceConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'ConpherenceConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
@ -4559,6 +4555,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialBlameRevisionField' => 'DifferentialStoredCustomField',
|
||||
'DifferentialBlockHeraldAction' => 'HeraldAction',
|
||||
'DifferentialBranchField' => 'DifferentialCustomField',
|
||||
'DifferentialChangeDetailMailView' => 'DifferentialMailView',
|
||||
'DifferentialChangeHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'DifferentialChangeType' => 'Phobject',
|
||||
'DifferentialChangesSinceLastUpdateField' => 'DifferentialCustomField',
|
||||
|
@ -4570,6 +4567,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject',
|
||||
'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer',
|
||||
'DifferentialChangesetListView' => 'AphrontView',
|
||||
'DifferentialChangesetOneUpMailRenderer' => 'DifferentialChangesetRenderer',
|
||||
'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer',
|
||||
'DifferentialChangesetOneUpTestRenderer' => 'DifferentialChangesetTestRenderer',
|
||||
'DifferentialChangesetParser' => 'Phobject',
|
||||
|
@ -4672,6 +4670,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorInlineCommentInterface',
|
||||
),
|
||||
'DifferentialInlineCommentEditController' => 'PhabricatorInlineCommentController',
|
||||
'DifferentialInlineCommentMailView' => 'DifferentialMailView',
|
||||
'DifferentialInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController',
|
||||
'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField',
|
||||
|
@ -4682,6 +4681,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialLintField' => 'DifferentialHarbormasterField',
|
||||
'DifferentialLintStatus' => 'Phobject',
|
||||
'DifferentialLocalCommitsView' => 'AphrontView',
|
||||
'DifferentialMailView' => 'Phobject',
|
||||
'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField',
|
||||
'DifferentialModernHunk' => 'DifferentialHunk',
|
||||
'DifferentialNextStepField' => 'DifferentialCustomField',
|
||||
|
@ -4799,6 +4799,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionCachedResolveRefsQuery' => 'DiffusionLowLevelQuery',
|
||||
'DiffusionChangeController' => 'DiffusionController',
|
||||
'DiffusionChangeHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'DiffusionCloneURIView' => 'AphrontView',
|
||||
'DiffusionCommandEngine' => 'Phobject',
|
||||
'DiffusionCommandEngineTestCase' => 'PhabricatorTestCase',
|
||||
'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField',
|
||||
|
@ -4845,6 +4846,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionController' => 'PhabricatorController',
|
||||
'DiffusionCreateCommentConduitAPIMethod' => 'DiffusionConduitAPIMethod',
|
||||
'DiffusionCreateRepositoriesCapability' => 'PhabricatorPolicyCapability',
|
||||
'DiffusionDaemonLockException' => 'Exception',
|
||||
'DiffusionDefaultEditCapability' => 'PhabricatorPolicyCapability',
|
||||
'DiffusionDefaultPushCapability' => 'PhabricatorPolicyCapability',
|
||||
'DiffusionDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||
|
@ -4891,6 +4893,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionLintController' => 'DiffusionController',
|
||||
'DiffusionLintCountQuery' => 'PhabricatorQuery',
|
||||
'DiffusionLintSaveRunner' => 'Phobject',
|
||||
'DiffusionLocalRepositoryFilter' => 'Phobject',
|
||||
'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod',
|
||||
'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery',
|
||||
'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery',
|
||||
|
@ -4914,8 +4917,6 @@ phutil_register_library_map(array(
|
|||
'DiffusionMercurialWireProtocolTests' => 'PhabricatorTestCase',
|
||||
'DiffusionMercurialWireSSHTestCase' => 'PhabricatorTestCase',
|
||||
'DiffusionMergedCommitsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
'DiffusionMirrorDeleteController' => 'DiffusionController',
|
||||
'DiffusionMirrorEditController' => 'DiffusionController',
|
||||
'DiffusionPathChange' => 'Phobject',
|
||||
'DiffusionPathChangeQuery' => 'Phobject',
|
||||
'DiffusionPathCompleteController' => 'DiffusionController',
|
||||
|
@ -4982,32 +4983,21 @@ phutil_register_library_map(array(
|
|||
'DiffusionRepositoryByIDRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'DiffusionRepositoryClusterEngine' => 'Phobject',
|
||||
'DiffusionRepositoryController' => 'DiffusionController',
|
||||
'DiffusionRepositoryCreateController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'DiffusionRepositoryDefaultController' => 'DiffusionController',
|
||||
'DiffusionRepositoryEditActionsController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditAutomationController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditBasicController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditBranchesController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryDocumentationManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
'DiffusionRepositoryEditController' => 'DiffusionController',
|
||||
'DiffusionRepositoryEditDangerousController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditDeleteController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditEncodingController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryEditDangerousController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryEditDeleteController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryEditEngine' => 'PhabricatorEditEngine',
|
||||
'DiffusionRepositoryEditHostingController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditMainController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditStagingController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditStorageController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditSubversionController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditproController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryHistoryManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositoryListController' => 'DiffusionController',
|
||||
'DiffusionRepositoryManageController' => 'DiffusionController',
|
||||
'DiffusionRepositoryManagePanelsController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryManagementPanel' => 'Phobject',
|
||||
'DiffusionRepositoryNewController' => 'DiffusionController',
|
||||
'DiffusionRepositoryPath' => 'Phobject',
|
||||
'DiffusionRepositoryPoliciesManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositoryRef' => 'Phobject',
|
||||
|
@ -5016,10 +5006,11 @@ phutil_register_library_map(array(
|
|||
'DiffusionRepositoryStagingManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositoryStatusManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositoryStorageManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositorySymbolsController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositorySubversionManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositorySymbolsManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||
'DiffusionRepositoryTag' => 'Phobject',
|
||||
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController',
|
||||
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryManageController',
|
||||
'DiffusionRepositoryURICredentialController' => 'DiffusionController',
|
||||
'DiffusionRepositoryURIDisableController' => 'DiffusionController',
|
||||
'DiffusionRepositoryURIEditController' => 'DiffusionController',
|
||||
'DiffusionRepositoryURIViewController' => 'DiffusionController',
|
||||
|
@ -6793,6 +6784,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorDebugController' => 'PhabricatorController',
|
||||
'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||
'PhabricatorDefaultSyntaxStyle' => 'PhabricatorSyntaxStyle',
|
||||
'PhabricatorDesktopNotificationsSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorDestructionEngine' => 'Phobject',
|
||||
'PhabricatorDestructionEngineExtension' => 'Phobject',
|
||||
|
@ -6870,6 +6862,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEditEngineSelectCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||
'PhabricatorEditEngineTokenizerCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||
'PhabricatorEditField' => 'Phobject',
|
||||
'PhabricatorEditPage' => 'Phobject',
|
||||
'PhabricatorEditType' => 'Phobject',
|
||||
'PhabricatorEditor' => 'Phobject',
|
||||
'PhabricatorElasticFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine',
|
||||
|
@ -7864,7 +7857,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementEditWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
|
@ -7881,13 +7873,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
|
||||
'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
|
||||
'PhabricatorRepositoryMirror' => array(
|
||||
'PhabricatorRepositoryDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorRepositoryMirror' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRepositoryMirrorEngine' => 'PhabricatorRepositoryEngine',
|
||||
'PhabricatorRepositoryMirrorPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorRepositoryMirrorQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorRepositoryParsedChange' => 'Phobject',
|
||||
'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine',
|
||||
'PhabricatorRepositoryPullEvent' => array(
|
||||
|
@ -8184,6 +8171,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSupportApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorSyntaxHighlighter' => 'Phobject',
|
||||
'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorSyntaxStyle' => 'Phobject',
|
||||
'PhabricatorSystemAction' => 'Phobject',
|
||||
'PhabricatorSystemActionEngine' => 'Phobject',
|
||||
'PhabricatorSystemActionGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
|
@ -8984,7 +8972,6 @@ phutil_register_library_map(array(
|
|||
'ReleephWorkRecordPickStatusConduitAPIMethod' => 'ReleephConduitAPIMethod',
|
||||
'RemarkupProcessConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'RepositoryConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'RepositoryCreateConduitAPIMethod' => 'RepositoryConduitAPIMethod',
|
||||
'RepositoryQueryConduitAPIMethod' => 'RepositoryConduitAPIMethod',
|
||||
'ShellLogView' => 'AphrontView',
|
||||
'SlowvoteConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
|
|
|
@ -484,7 +484,7 @@ final class AphrontRequest extends Phobject {
|
|||
pht(
|
||||
'This Phabricator install is configured as "%s", but you are '.
|
||||
'using the domain name "%s" to access a page which is trying to '.
|
||||
'set a cookie. Acccess Phabricator on the configured primary '.
|
||||
'set a cookie. Access Phabricator on the configured primary '.
|
||||
'domain or a configured alternate domain. Phabricator will not '.
|
||||
'set cookies on other domains for security reasons.',
|
||||
$configured_as,
|
||||
|
|
|
@ -10,6 +10,14 @@ final class AlmanacKeys extends Phobject {
|
|||
}
|
||||
|
||||
public static function getDeviceID() {
|
||||
// While running unit tests, ignore any configured device identity.
|
||||
try {
|
||||
PhabricatorTestCase::assertExecutingUnitTests();
|
||||
return null;
|
||||
} catch (Exception $ex) {
|
||||
// Continue normally.
|
||||
}
|
||||
|
||||
$device_id_path = self::getKeyPath('device.id');
|
||||
|
||||
if (Filesystem::pathExists($device_id_path)) {
|
||||
|
|
|
@ -624,11 +624,11 @@ abstract class PhabricatorApplication
|
|||
'(?P<id>[0-9]\d*)/)?'.
|
||||
'(?:'.
|
||||
'(?:'.
|
||||
'(?P<editAction>parameters|nodefault|nocreate|nomanage|comment)'.
|
||||
'(?P<editAction>parameters|nodefault|nocreate|nomanage|comment)/'.
|
||||
'|'.
|
||||
'(?:form/(?P<formKey>[^/]+))'.
|
||||
'(?:form/(?P<formKey>[^/]+)/)?(?:page/(?P<pageKey>[^/]+)/)?'.
|
||||
')'.
|
||||
'/)?';
|
||||
')?';
|
||||
}
|
||||
|
||||
protected function getQueryRoutePattern($base = null) {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
final class CelerityManagementSyntaxWorkflow
|
||||
extends CelerityManagementWorkflow {
|
||||
|
||||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('syntax')
|
||||
->setExamples('**syntax** [options]')
|
||||
->setSynopsis(pht('Rebuild syntax highlighting CSS.'))
|
||||
->setArguments(
|
||||
array());
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$styles = PhabricatorSyntaxStyle::getAllStyles();
|
||||
|
||||
$root = dirname(phutil_get_library_root('phabricator'));
|
||||
$root = $root.'/webroot/rsrc/css/syntax/';
|
||||
|
||||
foreach ($styles as $key => $style) {
|
||||
$content = $this->generateCSS($style);
|
||||
$path = $root.'/syntax-'.$key.'.css';
|
||||
Filesystem::writeFile($path, $content);
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Rebuilt "%s" syntax CSS.',
|
||||
basename($path)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function generateCSS(PhabricatorSyntaxStyle $style) {
|
||||
$key = $style->getSyntaxStyleKey();
|
||||
$provides = "syntax-{$key}-css";
|
||||
$generated = 'generated';
|
||||
|
||||
$header =
|
||||
"/**\n".
|
||||
" * @provides {$provides}\n".
|
||||
" * @{$generated}\n".
|
||||
" */\n\n";
|
||||
|
||||
$groups = array();
|
||||
$map = $style->getStyleMap();
|
||||
ksort($map);
|
||||
foreach ($map as $key => $value) {
|
||||
$groups[$value][] = $key;
|
||||
}
|
||||
|
||||
$rules = array();
|
||||
foreach ($groups as $body => $classes) {
|
||||
$parts = array();
|
||||
foreach ($classes as $class) {
|
||||
$parts[] = ".remarkup-code .{$class}";
|
||||
}
|
||||
$rules[] = implode(",\n", $parts)." {\n {$body}\n}";
|
||||
}
|
||||
$rules = implode("\n\n", $rules);
|
||||
|
||||
return $header.$rules."\n";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class ConduitEpochParameterType
|
||||
extends ConduitListParameterType {
|
||||
extends ConduitParameterType {
|
||||
|
||||
protected function getParameterValue(array $request, $key) {
|
||||
$value = parent::getParameterValue($request, $key);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class ConduitWildParameterType
|
||||
extends ConduitListParameterType {
|
||||
extends ConduitParameterType {
|
||||
|
||||
protected function getParameterTypeName() {
|
||||
return 'wild';
|
||||
|
|
|
@ -310,6 +310,10 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||
'notification.enabled' => $aphlict_reason,
|
||||
'notification.client-uri' => $aphlict_reason,
|
||||
'notification.server-uri' => $aphlict_reason,
|
||||
|
||||
'metamta.differential.unified-comment-context' => pht(
|
||||
'Inline comments are now always rendered with a limited amount '.
|
||||
'of context.'),
|
||||
);
|
||||
|
||||
return $ancient_config;
|
||||
|
|
|
@ -287,21 +287,6 @@ final class PhabricatorDifferentialConfigOptions
|
|||
'unified')
|
||||
->setDescription(
|
||||
pht("Format for inlined or attached patches: 'git' or 'unified'.")),
|
||||
$this->newOption(
|
||||
'metamta.differential.unified-comment-context',
|
||||
'bool',
|
||||
false)
|
||||
->setBoolOptions(
|
||||
array(
|
||||
pht('Show context'),
|
||||
pht('Do not show context'),
|
||||
))
|
||||
->setSummary(pht('Show diff context around inline comments in email.'))
|
||||
->setDescription(
|
||||
pht(
|
||||
'Normally, inline comments in emails are shown with a file and '.
|
||||
'line but without any diff context. Enabling this option adds '.
|
||||
'diff context and the comment thread.')),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1212,9 +1212,7 @@ final class DifferentialTransactionEditor
|
|||
}
|
||||
|
||||
if ($inlines) {
|
||||
$body->addTextSection(
|
||||
pht('INLINE COMMENTS'),
|
||||
$this->renderInlineCommentsForMail($object, $inlines));
|
||||
$this->appendInlineCommentsForMail($object, $inlines, $body);
|
||||
}
|
||||
|
||||
$changed_uri = $this->getChangedPriorToCommitURI();
|
||||
|
@ -1253,21 +1251,18 @@ final class DifferentialTransactionEditor
|
|||
$config_attach = PhabricatorEnv::getEnvConfig($config_key_attach);
|
||||
|
||||
if ($config_inline || $config_attach) {
|
||||
$patch_section = $this->renderPatchForMail($diff);
|
||||
$lines = count(phutil_split_lines($patch_section->getPlaintext()));
|
||||
$patch = $this->buildPatchForMail($diff);
|
||||
$lines = substr_count($patch, "\n");
|
||||
|
||||
if ($config_inline && ($lines <= $config_inline)) {
|
||||
$body->addTextSection(
|
||||
pht('CHANGE DETAILS'),
|
||||
$patch_section);
|
||||
$this->appendChangeDetailsForMail($object, $diff, $patch, $body);
|
||||
}
|
||||
|
||||
if ($config_attach) {
|
||||
$name = pht('D%s.%s.patch', $object->getID(), $diff->getID());
|
||||
$mime_type = 'text/x-patch; charset=utf-8';
|
||||
$body->addAttachment(
|
||||
new PhabricatorMetaMTAAttachment(
|
||||
$patch_section->getPlaintext(), $name, $mime_type));
|
||||
new PhabricatorMetaMTAAttachment($patch, $name, $mime_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1374,138 +1369,64 @@ final class DifferentialTransactionEditor
|
|||
return $result;
|
||||
}
|
||||
|
||||
protected function indentForMail(array $lines) {
|
||||
$indented = array();
|
||||
foreach ($lines as $line) {
|
||||
$indented[] = '> '.$line;
|
||||
}
|
||||
return $indented;
|
||||
}
|
||||
|
||||
protected function nestCommentHistory(
|
||||
DifferentialTransactionComment $comment, array $comments_by_line_number,
|
||||
array $users_by_phid) {
|
||||
|
||||
$nested = array();
|
||||
$previous_comments = $comments_by_line_number[$comment->getChangesetID()]
|
||||
[$comment->getLineNumber()];
|
||||
foreach ($previous_comments as $previous_comment) {
|
||||
if ($previous_comment->getID() >= $comment->getID()) {
|
||||
break;
|
||||
}
|
||||
$nested = $this->indentForMail(
|
||||
array_merge(
|
||||
$nested,
|
||||
explode("\n", $previous_comment->getContent())));
|
||||
$user = idx($users_by_phid, $previous_comment->getAuthorPHID(), null);
|
||||
if ($user) {
|
||||
array_unshift($nested, pht('%s wrote:', $user->getUserName()));
|
||||
}
|
||||
}
|
||||
|
||||
$nested = array_merge($nested, explode("\n", $comment->getContent()));
|
||||
return implode("\n", $nested);
|
||||
}
|
||||
|
||||
private function renderInlineCommentsForMail(
|
||||
private function appendInlineCommentsForMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $inlines) {
|
||||
array $inlines,
|
||||
PhabricatorMetaMTAMailBody $body) {
|
||||
|
||||
$context_key = 'metamta.differential.unified-comment-context';
|
||||
$show_context = PhabricatorEnv::getEnvConfig($context_key);
|
||||
|
||||
$changeset_ids = array();
|
||||
$line_numbers_by_changeset = array();
|
||||
foreach ($inlines as $inline) {
|
||||
$id = $inline->getComment()->getChangesetID();
|
||||
$changeset_ids[$id] = $id;
|
||||
$line_numbers_by_changeset[$id][] =
|
||||
$inline->getComment()->getLineNumber();
|
||||
}
|
||||
|
||||
$changesets = id(new DifferentialChangesetQuery())
|
||||
$section = id(new DifferentialInlineCommentMailView())
|
||||
->setViewer($this->getActor())
|
||||
->withIDs($changeset_ids)
|
||||
->needHunks(true)
|
||||
->execute();
|
||||
->setInlines($inlines)
|
||||
->buildMailSection();
|
||||
|
||||
$inline_groups = DifferentialTransactionComment::sortAndGroupInlines(
|
||||
$inlines,
|
||||
$changesets);
|
||||
$header = pht('INLINE COMMENTS');
|
||||
|
||||
if ($show_context) {
|
||||
$hunk_parser = new DifferentialHunkParser();
|
||||
$table = new DifferentialTransactionComment();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
$queries = array();
|
||||
foreach ($line_numbers_by_changeset as $id => $line_numbers) {
|
||||
$queries[] = qsprintf(
|
||||
$conn_r,
|
||||
'(changesetID = %d AND lineNumber IN (%Ld))',
|
||||
$id, $line_numbers);
|
||||
}
|
||||
$all_comments = id(new DifferentialTransactionComment())->loadAllWhere(
|
||||
'transactionPHID IS NOT NULL AND (%Q)', implode(' OR ', $queries));
|
||||
$comments_by_line_number = array();
|
||||
foreach ($all_comments as $comment) {
|
||||
$comments_by_line_number
|
||||
[$comment->getChangesetID()]
|
||||
[$comment->getLineNumber()]
|
||||
[$comment->getID()] = $comment;
|
||||
}
|
||||
$author_phids = mpull($all_comments, 'getAuthorPHID');
|
||||
$authors = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withPHIDs($author_phids)
|
||||
->execute();
|
||||
$authors_by_phid = mpull($authors, null, 'getPHID');
|
||||
}
|
||||
$section_text = "\n".$section->getPlaintext();
|
||||
|
||||
$section = new PhabricatorMetaMTAMailSection();
|
||||
foreach ($inline_groups as $changeset_id => $group) {
|
||||
$changeset = idx($changesets, $changeset_id);
|
||||
if (!$changeset) {
|
||||
continue;
|
||||
}
|
||||
$style = array(
|
||||
'margin: 6px 0 12px 0;',
|
||||
);
|
||||
|
||||
foreach ($group as $inline) {
|
||||
$comment = $inline->getComment();
|
||||
$file = $changeset->getFilename();
|
||||
$start = $comment->getLineNumber();
|
||||
$len = $comment->getLineLength();
|
||||
if ($len) {
|
||||
$range = $start.'-'.($start + $len);
|
||||
} else {
|
||||
$range = $start;
|
||||
}
|
||||
$section_html = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => implode(' ', $style),
|
||||
),
|
||||
$section->getHTML());
|
||||
|
||||
$inline_content = $comment->getContent();
|
||||
$body->addPlaintextSection($header, $section_text, false);
|
||||
$body->addHTMLSection($header, $section_html);
|
||||
}
|
||||
|
||||
if (!$show_context) {
|
||||
$section->addFragment("{$file}:{$range} {$inline_content}");
|
||||
} else {
|
||||
$patch = $hunk_parser->makeContextDiff(
|
||||
$changeset->getHunks(),
|
||||
$comment->getIsNewFile(),
|
||||
$comment->getLineNumber(),
|
||||
$comment->getLineLength(),
|
||||
1);
|
||||
$nested_comments = $this->nestCommentHistory(
|
||||
$inline->getComment(), $comments_by_line_number, $authors_by_phid);
|
||||
private function appendChangeDetailsForMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
DifferentialDiff $diff,
|
||||
$patch,
|
||||
PhabricatorMetaMTAMailBody $body) {
|
||||
|
||||
$section
|
||||
->addFragment('================')
|
||||
->addFragment(pht('Comment at: %s:%s', $file, $range))
|
||||
->addPlaintextFragment($patch)
|
||||
->addHTMLFragment($this->renderPatchHTMLForMail($patch))
|
||||
->addFragment('----------------')
|
||||
->addFragment($nested_comments)
|
||||
->addFragment(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
$section = id(new DifferentialChangeDetailMailView())
|
||||
->setViewer($this->getActor())
|
||||
->setDiff($diff)
|
||||
->setPatch($patch)
|
||||
->buildMailSection();
|
||||
|
||||
return $section;
|
||||
$header = pht('CHANGE DETAILS');
|
||||
|
||||
$section_text = "\n".$section->getPlaintext();
|
||||
|
||||
$style = array(
|
||||
'margin: 6px 0 12px 0;',
|
||||
);
|
||||
|
||||
$section_html = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => implode(' ', $style),
|
||||
),
|
||||
$section->getHTML());
|
||||
|
||||
$body->addPlaintextSection($header, $section_text, false);
|
||||
$body->addHTMLSection($header, $section_html);
|
||||
}
|
||||
|
||||
private function loadDiff($phid, $need_changesets = false) {
|
||||
|
@ -1766,20 +1687,14 @@ final class DifferentialTransactionEditor
|
|||
array('style' => 'font-family: monospace;'), $patch);
|
||||
}
|
||||
|
||||
private function renderPatchForMail(DifferentialDiff $diff) {
|
||||
private function buildPatchForMail(DifferentialDiff $diff) {
|
||||
$format = PhabricatorEnv::getEnvConfig('metamta.differential.patch-format');
|
||||
|
||||
$patch = id(new DifferentialRawDiffRenderer())
|
||||
return id(new DifferentialRawDiffRenderer())
|
||||
->setViewer($this->getActor())
|
||||
->setFormat($format)
|
||||
->setChangesets($diff->getChangesets())
|
||||
->buildPatch();
|
||||
|
||||
$section = new PhabricatorMetaMTAMailSection();
|
||||
$section->addHTMLFragment($this->renderPatchHTMLForMail($patch));
|
||||
$section->addPlaintextFragment($patch);
|
||||
|
||||
return $section;
|
||||
}
|
||||
|
||||
protected function willPublish(PhabricatorLiskDAO $object, array $xactions) {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialChangeDetailMailView
|
||||
extends DifferentialMailView {
|
||||
|
||||
private $viewer;
|
||||
private $diff;
|
||||
private $patch;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function setDiff(DifferentialDiff $diff) {
|
||||
$this->diff = $diff;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDiff() {
|
||||
return $this->diff;
|
||||
}
|
||||
|
||||
public function setPatch($patch) {
|
||||
$this->patch = $patch;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPatch() {
|
||||
return $this->patch;
|
||||
}
|
||||
|
||||
public function buildMailSection() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$diff = $this->getDiff();
|
||||
|
||||
$engine = new PhabricatorMarkupEngine();
|
||||
|
||||
$out = array();
|
||||
foreach ($diff->getChangesets() as $changeset) {
|
||||
$parser = id(new DifferentialChangesetParser())
|
||||
->setUser($viewer)
|
||||
->setChangeset($changeset)
|
||||
->setLinesOfContext(2)
|
||||
->setMarkupEngine($engine);
|
||||
|
||||
$parser->setRenderer(new DifferentialChangesetOneUpMailRenderer());
|
||||
$block = $parser->render();
|
||||
|
||||
$filename = $changeset->getFilename();
|
||||
$filename = $this->renderHeaderBold($filename);
|
||||
$header = $this->renderHeaderBlock($filename);
|
||||
|
||||
$out[] = $this->renderContentBox(
|
||||
array(
|
||||
$header,
|
||||
$this->renderCodeBlock($block),
|
||||
));
|
||||
}
|
||||
|
||||
$out = phutil_implode_html(phutil_tag('br'), $out);
|
||||
|
||||
$patch_html = $out;
|
||||
|
||||
$patch_text = $this->getPatch();
|
||||
|
||||
return id(new PhabricatorMetaMTAMailSection())
|
||||
->addPlaintextFragment($patch_text)
|
||||
->addHTMLFragment($patch_html);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,477 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialInlineCommentMailView
|
||||
extends DifferentialMailView {
|
||||
|
||||
private $viewer;
|
||||
private $inlines;
|
||||
private $changesets;
|
||||
private $authors;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function setInlines($inlines) {
|
||||
$this->inlines = $inlines;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInlines() {
|
||||
return $this->inlines;
|
||||
}
|
||||
|
||||
public function buildMailSection() {
|
||||
$inlines = $this->getInlines();
|
||||
|
||||
$comments = mpull($inlines, 'getComment');
|
||||
$comments = mpull($comments, null, 'getPHID');
|
||||
$parents = $this->loadParents($comments);
|
||||
$all_comments = $comments + $parents;
|
||||
|
||||
$this->changesets = $this->loadChangesets($all_comments);
|
||||
$this->authors = $this->loadAuthors($all_comments);
|
||||
$groups = $this->groupInlines($inlines);
|
||||
|
||||
$hunk_parser = new DifferentialHunkParser();
|
||||
|
||||
$spacer_text = null;
|
||||
$spacer_html = phutil_tag('br');
|
||||
|
||||
$section = new PhabricatorMetaMTAMailSection();
|
||||
|
||||
$last_group_key = last_key($groups);
|
||||
foreach ($groups as $changeset_id => $group) {
|
||||
$changeset = $this->getChangeset($changeset_id);
|
||||
if (!$changeset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$is_last_group = ($changeset_id == $last_group_key);
|
||||
|
||||
$last_inline_key = last_key($group);
|
||||
foreach ($group as $inline_key => $inline) {
|
||||
$comment = $inline->getComment();
|
||||
$parent_phid = $comment->getReplyToCommentPHID();
|
||||
|
||||
$is_last_inline = ($inline_key == $last_inline_key);
|
||||
|
||||
$context_text = null;
|
||||
$context_html = null;
|
||||
|
||||
if ($parent_phid) {
|
||||
$parent = idx($parents, $parent_phid);
|
||||
if ($parent) {
|
||||
$context_text = $this->renderInline($parent, false, true);
|
||||
$context_html = $this->renderInline($parent, true, true);
|
||||
}
|
||||
} else {
|
||||
$patch_text = $this->getPatch($hunk_parser, $comment, false);
|
||||
$context_text = $this->renderPatch($comment, $patch_text, false);
|
||||
|
||||
$patch_html = $this->getPatch($hunk_parser, $comment, true);
|
||||
$context_html = $this->renderPatch($comment, $patch_html, true);
|
||||
}
|
||||
|
||||
$render_text = $this->renderInline($comment, false, false);
|
||||
$render_html = $this->renderInline($comment, true, false);
|
||||
|
||||
$section->addPlaintextFragment($context_text);
|
||||
$section->addPlaintextFragment($spacer_text);
|
||||
$section->addPlaintextFragment($render_text);
|
||||
|
||||
$html_fragment = $this->renderContentBox(
|
||||
array(
|
||||
$context_html,
|
||||
$render_html,
|
||||
));
|
||||
|
||||
$section->addHTMLFragment($html_fragment);
|
||||
|
||||
if (!$is_last_group || !$is_last_inline) {
|
||||
$section->addPlaintextFragment($spacer_text);
|
||||
$section->addHTMLFragment($spacer_html);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $section;
|
||||
}
|
||||
|
||||
private function loadChangesets(array $comments) {
|
||||
if (!$comments) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
foreach ($comments as $comment) {
|
||||
$ids[] = $comment->getChangesetID();
|
||||
}
|
||||
|
||||
$changesets = id(new DifferentialChangesetQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($ids)
|
||||
->needHunks(true)
|
||||
->execute();
|
||||
|
||||
return mpull($changesets, null, 'getID');
|
||||
}
|
||||
|
||||
private function loadParents(array $comments) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$phids = array();
|
||||
foreach ($comments as $comment) {
|
||||
$parent_phid = $comment->getReplyToCommentPHID();
|
||||
if (!$parent_phid) {
|
||||
continue;
|
||||
}
|
||||
$phids[] = $parent_phid;
|
||||
}
|
||||
|
||||
if (!$phids) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$parents = id(new DifferentialDiffInlineCommentQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
|
||||
return mpull($parents, null, 'getPHID');
|
||||
}
|
||||
|
||||
private function loadAuthors(array $comments) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$phids = array();
|
||||
foreach ($comments as $comment) {
|
||||
$author_phid = $comment->getAuthorPHID();
|
||||
if (!$author_phid) {
|
||||
continue;
|
||||
}
|
||||
$phids[] = $author_phid;
|
||||
}
|
||||
|
||||
if (!$phids) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $viewer->loadHandles($phids);
|
||||
}
|
||||
|
||||
private function groupInlines(array $inlines) {
|
||||
return DifferentialTransactionComment::sortAndGroupInlines(
|
||||
$inlines,
|
||||
$this->changesets);
|
||||
}
|
||||
|
||||
private function renderInline(
|
||||
DifferentialTransactionComment $comment,
|
||||
$is_html,
|
||||
$is_quote) {
|
||||
|
||||
$changeset = $this->getChangeset($comment->getChangesetID());
|
||||
if (!$changeset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$content = $comment->getContent();
|
||||
$content = $this->renderRemarkupContent($content, $is_html);
|
||||
|
||||
if ($is_quote) {
|
||||
$header = $this->renderHeader($comment, $is_html, true);
|
||||
} else {
|
||||
$header = null;
|
||||
}
|
||||
|
||||
if ($is_html) {
|
||||
$style = array(
|
||||
'margin: 8px 0;',
|
||||
'padding: 0 12px;',
|
||||
);
|
||||
|
||||
if ($is_quote) {
|
||||
$style[] = 'color: #74777D;';
|
||||
}
|
||||
|
||||
$content = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => implode(' ', $style),
|
||||
),
|
||||
$content);
|
||||
}
|
||||
|
||||
$parts = array(
|
||||
$header,
|
||||
"\n",
|
||||
$content,
|
||||
);
|
||||
|
||||
if (!$is_html) {
|
||||
$parts = implode('', $parts);
|
||||
$parts = trim($parts);
|
||||
}
|
||||
|
||||
if ($is_quote) {
|
||||
if ($is_html) {
|
||||
$parts = $this->quoteHTML($parts);
|
||||
} else {
|
||||
$parts = $this->quoteText($parts);
|
||||
}
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
private function renderRemarkupContent($content, $is_html) {
|
||||
$viewer = $this->getViewer();
|
||||
$production_uri = PhabricatorEnv::getProductionURI('/');
|
||||
|
||||
if ($is_html) {
|
||||
$mode = PhutilRemarkupEngine::MODE_HTML_MAIL;
|
||||
} else {
|
||||
$mode = PhutilRemarkupEngine::MODE_TEXT;
|
||||
}
|
||||
|
||||
$attributes = array(
|
||||
'style' => 'padding: 0; margin: 8px;',
|
||||
);
|
||||
|
||||
$engine = PhabricatorMarkupEngine::newMarkupEngine(array())
|
||||
->setConfig('viewer', $viewer)
|
||||
->setConfig('uri.base', $production_uri)
|
||||
->setConfig('default.p.attributes', $attributes)
|
||||
->setMode($mode);
|
||||
|
||||
try {
|
||||
return $engine->markupText($content);
|
||||
} catch (Exception $ex) {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
private function getChangeset($id) {
|
||||
return idx($this->changesets, $id);
|
||||
}
|
||||
|
||||
private function getAuthor($phid) {
|
||||
if (isset($this->authors[$phid])) {
|
||||
return $this->authors[$phid];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function quoteText($block) {
|
||||
$block = phutil_split_lines($block);
|
||||
foreach ($block as $key => $line) {
|
||||
$block[$key] = '> '.$line;
|
||||
}
|
||||
|
||||
return implode('', $block);
|
||||
}
|
||||
|
||||
private function quoteHTML($block) {
|
||||
$styles = array(
|
||||
'padding: 0;',
|
||||
'background: #F7F7F7;',
|
||||
'border-color: #e3e4e8;',
|
||||
'border-style: solid;',
|
||||
'border-width: 0 0 1px 0;',
|
||||
'margin: 0;',
|
||||
);
|
||||
|
||||
$styles = implode(' ', $styles);
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => $styles,
|
||||
),
|
||||
$block);
|
||||
}
|
||||
|
||||
private function getPatch(
|
||||
DifferentialHunkParser $parser,
|
||||
DifferentialTransactionComment $comment,
|
||||
$is_html) {
|
||||
|
||||
$changeset = $this->getChangeset($comment->getChangesetID());
|
||||
$is_new = $comment->getIsNewFile();
|
||||
$start = $comment->getLineNumber();
|
||||
$length = $comment->getLineLength();
|
||||
|
||||
// By default, show one line of context around the target inline.
|
||||
$context = 1;
|
||||
|
||||
// If the inline is at least 3 lines long, don't show any extra context.
|
||||
if ($length >= 2) {
|
||||
$context = 0;
|
||||
}
|
||||
|
||||
// If the inline is more than 7 lines long, only show the first 7 lines.
|
||||
if ($length >= 6) {
|
||||
$length = 6;
|
||||
}
|
||||
|
||||
if (!$is_html) {
|
||||
$hunks = $changeset->getHunks();
|
||||
$patch = $parser->makeContextDiff(
|
||||
$hunks,
|
||||
$is_new,
|
||||
$start,
|
||||
$length,
|
||||
$context);
|
||||
$patch = phutil_split_lines($patch);
|
||||
|
||||
// Remove the "@@ -x,y +u,v @@" line.
|
||||
array_shift($patch);
|
||||
|
||||
return implode('', $patch);
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$engine = new PhabricatorMarkupEngine();
|
||||
|
||||
if ($is_new) {
|
||||
$offset_mode = 'new';
|
||||
} else {
|
||||
$offset_mode = 'old';
|
||||
}
|
||||
|
||||
$parser = id(new DifferentialChangesetParser())
|
||||
->setUser($viewer)
|
||||
->setChangeset($changeset)
|
||||
->setOffsetMode($offset_mode)
|
||||
->setMarkupEngine($engine);
|
||||
|
||||
$parser->setRenderer(new DifferentialChangesetOneUpMailRenderer());
|
||||
|
||||
return $parser->render(
|
||||
$start - $context,
|
||||
$length + 1 + (2 * $context),
|
||||
array());
|
||||
}
|
||||
|
||||
private function renderPatch(
|
||||
DifferentialTransactionComment $comment,
|
||||
$patch,
|
||||
$is_html) {
|
||||
|
||||
if ($is_html) {
|
||||
$patch = $this->renderCodeBlock($patch);
|
||||
}
|
||||
|
||||
$header = $this->renderHeader($comment, $is_html, false);
|
||||
|
||||
$patch = array(
|
||||
$header,
|
||||
"\n",
|
||||
$patch,
|
||||
);
|
||||
|
||||
if (!$is_html) {
|
||||
$patch = implode('', $patch);
|
||||
$patch = $this->quoteText($patch);
|
||||
} else {
|
||||
$patch = $this->quoteHTML($patch);
|
||||
}
|
||||
|
||||
return $patch;
|
||||
}
|
||||
|
||||
private function renderHeader(
|
||||
DifferentialTransactionComment $comment,
|
||||
$is_html,
|
||||
$with_author) {
|
||||
|
||||
$changeset = $this->getChangeset($comment->getChangesetID());
|
||||
$path = $changeset->getFilename();
|
||||
|
||||
// Only show the filename.
|
||||
$path = basename($path);
|
||||
|
||||
$start = $comment->getLineNumber();
|
||||
$length = $comment->getLineLength();
|
||||
if ($length) {
|
||||
$range = pht('%s-%s', $start, $start + $length);
|
||||
} else {
|
||||
$range = $start;
|
||||
}
|
||||
|
||||
$header = "{$path}:{$range}";
|
||||
if ($is_html) {
|
||||
$header = $this->renderHeaderBold($header);
|
||||
}
|
||||
|
||||
if ($with_author) {
|
||||
$author = $this->getAuthor($comment->getAuthorPHID());
|
||||
} else {
|
||||
$author = null;
|
||||
}
|
||||
|
||||
if ($author) {
|
||||
$byline = $author->getName();
|
||||
|
||||
if ($is_html) {
|
||||
$byline = $this->renderHeaderBold($byline);
|
||||
}
|
||||
|
||||
$header = pht('%s wrote in %s', $byline, $header);
|
||||
}
|
||||
|
||||
if ($is_html) {
|
||||
$link_href = $this->getInlineURI($comment);
|
||||
if ($link_href) {
|
||||
$link_style = array(
|
||||
'float: right;',
|
||||
'text-decoration: none;',
|
||||
);
|
||||
|
||||
$link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'style' => implode(' ', $link_style),
|
||||
'href' => $link_href,
|
||||
),
|
||||
pht('View Inline'));
|
||||
} else {
|
||||
$link = null;
|
||||
}
|
||||
|
||||
$header = $this->renderHeaderBlock(array($link, $header));
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
private function getInlineURI(DifferentialTransactionComment $comment) {
|
||||
$changeset = $this->getChangeset($comment->getChangesetID());
|
||||
if (!$changeset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$diff = $changeset->getDiff();
|
||||
if (!$diff) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$revision = $diff->getRevision();
|
||||
if (!$revision) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$link_href = '/'.$revision->getMonogram().'#inline-'.$comment->getID();
|
||||
$link_href = PhabricatorEnv::getProductionURI($link_href);
|
||||
|
||||
return $link_href;
|
||||
}
|
||||
|
||||
|
||||
}
|
62
src/applications/differential/mail/DifferentialMailView.php
Normal file
62
src/applications/differential/mail/DifferentialMailView.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
abstract class DifferentialMailView
|
||||
extends Phobject {
|
||||
|
||||
protected function renderCodeBlock($block) {
|
||||
$style = array(
|
||||
'font: 11px/15px "Menlo", "Consolas", "Monaco", monospace;',
|
||||
'white-space: pre-wrap;',
|
||||
'clear: both;',
|
||||
'padding: 4px 0;',
|
||||
'margin: 0;',
|
||||
);
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => implode(' ', $style),
|
||||
),
|
||||
$block);
|
||||
}
|
||||
|
||||
protected function renderHeaderBlock($block) {
|
||||
$style = array(
|
||||
'color: #74777d;',
|
||||
'background: #eff2f4;',
|
||||
'padding: 6px 8px;',
|
||||
'overflow: hidden;',
|
||||
);
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => implode(' ', $style),
|
||||
),
|
||||
$block);
|
||||
}
|
||||
|
||||
protected function renderHeaderBold($content) {
|
||||
return phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'style' => 'color: #4b4d51; font-weight: bold;',
|
||||
),
|
||||
$content);
|
||||
}
|
||||
|
||||
protected function renderContentBox($content) {
|
||||
$style = array(
|
||||
'border: 1px solid #C7CCD9;',
|
||||
'border-radius: 3px;',
|
||||
);
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => implode(' ', $style),
|
||||
),
|
||||
$content);
|
||||
}
|
||||
|
||||
}
|
|
@ -50,10 +50,12 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
private $showEditAndReplyLinks = true;
|
||||
private $canMarkDone;
|
||||
private $objectOwnerPHID;
|
||||
private $offsetMode;
|
||||
|
||||
private $rangeStart;
|
||||
private $rangeEnd;
|
||||
private $mask;
|
||||
private $linesOfContext = 8;
|
||||
|
||||
private $highlightEngine;
|
||||
|
||||
|
@ -138,6 +140,15 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
return $this->objectOwnerPHID;
|
||||
}
|
||||
|
||||
public function setOffsetMode($offset_mode) {
|
||||
$this->offsetMode = $offset_mode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOffsetMode() {
|
||||
return $this->offsetMode;
|
||||
}
|
||||
|
||||
public static function getDefaultRendererForViewer(PhabricatorUser $viewer) {
|
||||
$prefs = $viewer->loadPreferences();
|
||||
$pref_unified = PhabricatorUserPreferences::PREFERENCE_DIFF_UNIFIED;
|
||||
|
@ -185,8 +196,6 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
const ATTR_WHITELINES = 'attr:white';
|
||||
const ATTR_MOVEAWAY = 'attr:moveaway';
|
||||
|
||||
const LINES_CONTEXT = 8;
|
||||
|
||||
const WHITESPACE_SHOW_ALL = 'show-all';
|
||||
const WHITESPACE_IGNORE_TRAILING = 'ignore-trailing';
|
||||
const WHITESPACE_IGNORE_MOST = 'ignore-most';
|
||||
|
@ -217,6 +226,16 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setLinesOfContext($lines_of_context) {
|
||||
$this->linesOfContext = $lines_of_context;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinesOfContext() {
|
||||
return $this->linesOfContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure which Changeset comments added to the right side of the visible
|
||||
* diff will be attached to. The ID must be the ID of a real Differential
|
||||
|
@ -714,8 +733,10 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
self::ATTR_MOVEAWAY => $moveaway,
|
||||
));
|
||||
|
||||
$lines_context = $this->getLinesOfContext();
|
||||
|
||||
$hunk_parser->generateIntraLineDiffs();
|
||||
$hunk_parser->generateVisibileLinesMask();
|
||||
$hunk_parser->generateVisibileLinesMask($lines_context);
|
||||
|
||||
$this->setOldLines($hunk_parser->getOldLines());
|
||||
$this->setNewLines($hunk_parser->getNewLines());
|
||||
|
@ -829,6 +850,22 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
}
|
||||
|
||||
$this->tryCacheStuff();
|
||||
|
||||
// If we're rendering in an offset mode, treat the range numbers as line
|
||||
// numbers instead of rendering offsets.
|
||||
$offset_mode = $this->getOffsetMode();
|
||||
if ($offset_mode) {
|
||||
if ($offset_mode == 'new') {
|
||||
$offset_map = $this->new;
|
||||
} else {
|
||||
$offset_map = $this->old;
|
||||
}
|
||||
|
||||
$range_end = $this->getOffset($offset_map, $range_start + $range_len);
|
||||
$range_start = $this->getOffset($offset_map, $range_start);
|
||||
$range_len = ($range_end - $range_start);
|
||||
}
|
||||
|
||||
$render_pch = $this->shouldRenderPropertyChangeHeader($this->changeset);
|
||||
|
||||
$rows = max(
|
||||
|
@ -933,6 +970,7 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
$old_mask = array();
|
||||
$new_mask = array();
|
||||
$feedback_mask = array();
|
||||
$lines_context = $this->getLinesOfContext();
|
||||
|
||||
if ($this->comments) {
|
||||
// If there are any comments which appear in sections of the file which
|
||||
|
@ -975,10 +1013,10 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
|
||||
}
|
||||
|
||||
$start = max($comment->getLineNumber() - self::LINES_CONTEXT, 0);
|
||||
$start = max($comment->getLineNumber() - $lines_context, 0);
|
||||
$end = $comment->getLineNumber() +
|
||||
$comment->getLineLength() +
|
||||
self::LINES_CONTEXT;
|
||||
$lines_context;
|
||||
for ($ii = $start; $ii <= $end; $ii++) {
|
||||
if ($new_side) {
|
||||
$new_mask[$ii] = true;
|
||||
|
@ -1163,6 +1201,8 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
$range_start,
|
||||
$range_len) {
|
||||
|
||||
$lines_context = $this->getLinesOfContext();
|
||||
|
||||
// Calculate gaps and mask first
|
||||
$gaps = array();
|
||||
$gap_start = 0;
|
||||
|
@ -1173,7 +1213,7 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
if (isset($base_mask[$ii])) {
|
||||
if ($in_gap) {
|
||||
$gap_length = $ii - $gap_start;
|
||||
if ($gap_length <= self::LINES_CONTEXT) {
|
||||
if ($gap_length <= $lines_context) {
|
||||
for ($jj = $gap_start; $jj <= $gap_start + $gap_length; $jj++) {
|
||||
$base_mask[$jj] = true;
|
||||
}
|
||||
|
@ -1632,5 +1672,21 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
return $results;
|
||||
}
|
||||
|
||||
private function getOffset(array $map, $line) {
|
||||
if (!$map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$line = (int)$line;
|
||||
foreach ($map as $key => $spec) {
|
||||
if ($spec && isset($spec['line'])) {
|
||||
if ((int)$spec['line'] >= $line) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -353,8 +353,7 @@ final class DifferentialHunkParser extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function generateVisibileLinesMask() {
|
||||
$lines_context = DifferentialChangesetParser::LINES_CONTEXT;
|
||||
public function generateVisibileLinesMask($lines_context) {
|
||||
$old = $this->getOldLines();
|
||||
$new = $this->getNewLines();
|
||||
$max_length = max(count($old), count($new));
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialChangesetOneUpMailRenderer
|
||||
extends DifferentialChangesetRenderer {
|
||||
|
||||
public function isOneUpRenderer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getRendererTableClass() {
|
||||
return 'diff-1up-mail';
|
||||
}
|
||||
|
||||
public function getRendererKey() {
|
||||
return '1up-mail';
|
||||
}
|
||||
|
||||
protected function renderChangeTypeHeader($force) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function renderUndershieldHeader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function renderShield($message, $force = 'default') {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function renderPropertyChangeHeader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function renderFileChange(
|
||||
$old_file = null,
|
||||
$new_file = null,
|
||||
$id = 0,
|
||||
$vs = 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function renderTextChange(
|
||||
$range_start,
|
||||
$range_len,
|
||||
$rows) {
|
||||
|
||||
$primitives = $this->buildPrimitives($range_start, $range_len);
|
||||
return $this->renderPrimitives($primitives, $rows);
|
||||
}
|
||||
|
||||
protected function renderPrimitives(array $primitives, $rows) {
|
||||
$out = array();
|
||||
|
||||
$context_style = array(
|
||||
'background: #F7F7F7;',
|
||||
'color: #74777D;',
|
||||
'border-style: dashed;',
|
||||
'border-color: #C7CCD9;',
|
||||
'border-width: 1px 0;',
|
||||
);
|
||||
|
||||
$context_style = implode(' ', $context_style);
|
||||
|
||||
foreach ($primitives as $k => $p) {
|
||||
$type = $p['type'];
|
||||
switch ($type) {
|
||||
case 'old':
|
||||
case 'new':
|
||||
case 'old-file':
|
||||
case 'new-file':
|
||||
$is_old = ($type == 'old' || $type == 'old-file');
|
||||
|
||||
if ($is_old) {
|
||||
if ($p['htype']) {
|
||||
$style = 'background: #ffd0d0;';
|
||||
} else {
|
||||
$style = null;
|
||||
}
|
||||
} else {
|
||||
if ($p['htype']) {
|
||||
$style = 'background: #d0ffd0;';
|
||||
} else {
|
||||
$style = null;
|
||||
}
|
||||
}
|
||||
|
||||
$out[] = array(
|
||||
'style' => $style,
|
||||
'render' => $p['render'],
|
||||
'text' => (string)$p['render'],
|
||||
);
|
||||
break;
|
||||
case 'context':
|
||||
// NOTE: These are being included with no text so they get stripped
|
||||
// in the header and footer.
|
||||
$out[] = array(
|
||||
'style' => $context_style,
|
||||
'render' => '...',
|
||||
'text' => '',
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all leading and trailing empty lines, since these just look kind
|
||||
// of weird in mail.
|
||||
foreach ($out as $key => $line) {
|
||||
if (!strlen(trim($line['text']))) {
|
||||
unset($out[$key]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$keys = array_reverse(array_keys($out));
|
||||
foreach ($keys as $key) {
|
||||
$line = $out[$key];
|
||||
if (!strlen(trim($line['text']))) {
|
||||
unset($out[$key]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the user has commented on an empty line in the middle of a bunch of
|
||||
// other empty lines, emit an explicit marker instead of just rendering
|
||||
// nothing.
|
||||
if (!$out) {
|
||||
$out[] = array(
|
||||
'style' => 'color: #888888;',
|
||||
'render' => pht('(Empty.)'),
|
||||
);
|
||||
}
|
||||
|
||||
$render = array();
|
||||
foreach ($out as $line) {
|
||||
$style = $line['style'];
|
||||
$style = "padding: 0 8px; margin: 0 4px; {$style}";
|
||||
|
||||
$render[] = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'style' => $style,
|
||||
),
|
||||
$line['render']);
|
||||
}
|
||||
|
||||
$style_map = id(new PhabricatorDefaultSyntaxStyle())
|
||||
->getRemarkupStyleMap();
|
||||
|
||||
$styled_body = id(new PhutilPygmentizeParser())
|
||||
->setMap($style_map)
|
||||
->parse((string)hsprintf('%s', $render));
|
||||
|
||||
return phutil_safe_html($styled_body);
|
||||
}
|
||||
|
||||
}
|
|
@ -58,15 +58,15 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
} else {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_ACCEPT,
|
||||
'dark',
|
||||
'bluegrey',
|
||||
pht('Accepted Prior Diff'));
|
||||
}
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER:
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_ACCEPT,
|
||||
'dark',
|
||||
'fa-check-circle-o',
|
||||
'bluegrey',
|
||||
pht('Accepted Prior Diff'));
|
||||
break;
|
||||
|
||||
|
@ -78,28 +78,29 @@ final class DifferentialReviewersView extends AphrontView {
|
|||
pht('Requested Changes'));
|
||||
} else {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_REJECT,
|
||||
'dark',
|
||||
'fa-times-circle-o',
|
||||
'bluegrey',
|
||||
pht('Requested Changes to Prior Diff'));
|
||||
}
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_REJECTED_OLDER:
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_REJECT,
|
||||
'dark',
|
||||
'fa-times-circle-o',
|
||||
'bluegrey',
|
||||
pht('Rejected Prior Diff'));
|
||||
break;
|
||||
|
||||
case DifferentialReviewerStatus::STATUS_COMMENTED:
|
||||
if ($is_current) {
|
||||
$item->setIcon(
|
||||
PHUIStatusItemView::ICON_INFO,
|
||||
'fa-question-circle',
|
||||
'blue',
|
||||
pht('Commented'));
|
||||
} else {
|
||||
$item->setIcon(
|
||||
'info-dark',
|
||||
'fa-question-circle-o',
|
||||
'bluegrey',
|
||||
pht('Commented Previously'));
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -57,11 +57,8 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||
'/diffusion/' => array(
|
||||
$this->getQueryRoutePattern()
|
||||
=> 'DiffusionRepositoryListController',
|
||||
$this->getEditRoutePattern('editpro/') =>
|
||||
'DiffusionRepositoryEditproController',
|
||||
'new/' => 'DiffusionRepositoryNewController',
|
||||
'(?P<edit>create)/' => 'DiffusionRepositoryCreateController',
|
||||
'(?P<edit>import)/' => 'DiffusionRepositoryCreateController',
|
||||
$this->getEditRoutePattern('edit/') =>
|
||||
'DiffusionRepositoryEditController',
|
||||
'pushlog/' => array(
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
|
||||
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
|
||||
|
@ -90,40 +87,24 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||
'commit/(?P<commit>[a-z0-9]+)/edit/'
|
||||
=> 'DiffusionCommitEditController',
|
||||
'manage/(?:(?P<panel>[^/]+)/)?'
|
||||
=> 'DiffusionRepositoryManageController',
|
||||
=> 'DiffusionRepositoryManagePanelsController',
|
||||
'uri/' => array(
|
||||
'view/(?P<id>[0-9]\d*)/' => 'DiffusionRepositoryURIViewController',
|
||||
'disable/(?P<id>[0-9]\d*)/'
|
||||
=> 'DiffusionRepositoryURIDisableController',
|
||||
$this->getEditRoutePattern('edit/')
|
||||
=> 'DiffusionRepositoryURIEditController',
|
||||
'credential/(?P<id>[0-9]\d*)/(?P<action>edit|remove)/'
|
||||
=> 'DiffusionRepositoryURICredentialController',
|
||||
),
|
||||
'edit/' => array(
|
||||
'' => 'DiffusionRepositoryEditMainController',
|
||||
'basic/' => 'DiffusionRepositoryEditBasicController',
|
||||
'encoding/' => 'DiffusionRepositoryEditEncodingController',
|
||||
'activate/' => 'DiffusionRepositoryEditActivateController',
|
||||
'dangerous/' => 'DiffusionRepositoryEditDangerousController',
|
||||
'branches/' => 'DiffusionRepositoryEditBranchesController',
|
||||
'subversion/' => 'DiffusionRepositoryEditSubversionController',
|
||||
'actions/' => 'DiffusionRepositoryEditActionsController',
|
||||
'(?P<edit>remote)/' => 'DiffusionRepositoryCreateController',
|
||||
'(?P<edit>policy)/' => 'DiffusionRepositoryCreateController',
|
||||
'storage/' => 'DiffusionRepositoryEditStorageController',
|
||||
'delete/' => 'DiffusionRepositoryEditDeleteController',
|
||||
'hosting/' => 'DiffusionRepositoryEditHostingController',
|
||||
'(?P<serve>serve)/' => 'DiffusionRepositoryEditHostingController',
|
||||
'update/' => 'DiffusionRepositoryEditUpdateController',
|
||||
'symbol/' => 'DiffusionRepositorySymbolsController',
|
||||
'staging/' => 'DiffusionRepositoryEditStagingController',
|
||||
'automation/' => 'DiffusionRepositoryEditAutomationController',
|
||||
'testautomation/' => 'DiffusionRepositoryTestAutomationController',
|
||||
),
|
||||
'pathtree/(?P<dblob>.*)' => 'DiffusionPathTreeController',
|
||||
'mirror/' => array(
|
||||
'edit/(?:(?P<id>\d+)/)?' => 'DiffusionMirrorEditController',
|
||||
'delete/(?P<id>\d+)/' => 'DiffusionMirrorDeleteController',
|
||||
),
|
||||
),
|
||||
|
||||
// NOTE: This must come after the rule above; it just gives us a
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionMirrorDeleteController
|
||||
extends DiffusionController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContext();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$mirror = id(new PhabricatorRepositoryMirrorQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$mirror) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$mirror->delete();
|
||||
return id(new AphrontReloadResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Really delete mirror?'))
|
||||
->appendChild(
|
||||
pht('Phabricator will stop pushing updates to this mirror.'))
|
||||
->addSubmitButton(pht('Delete Mirror'))
|
||||
->addCancelButton($edit_uri);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionMirrorEditController
|
||||
extends DiffusionController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContext();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
if ($request->getURIData('id')) {
|
||||
$mirror = id(new PhabricatorRepositoryMirrorQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$mirror) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$is_new = false;
|
||||
} else {
|
||||
$mirror = PhabricatorRepositoryMirror::initializeNewMirror($viewer)
|
||||
->setRepositoryPHID($repository->getPHID())
|
||||
->attachRepository($repository);
|
||||
$is_new = true;
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors');
|
||||
|
||||
$v_remote = $mirror->getRemoteURI();
|
||||
$e_remote = true;
|
||||
|
||||
$v_credentials = $mirror->getCredentialPHID();
|
||||
$e_credentials = null;
|
||||
|
||||
$credentials = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withIsDestroyed(false)
|
||||
->execute();
|
||||
|
||||
$errors = array();
|
||||
if ($request->isFormPost()) {
|
||||
$v_remote = $request->getStr('remoteURI');
|
||||
if (strlen($v_remote)) {
|
||||
try {
|
||||
PhabricatorRepository::assertValidRemoteURI($v_remote);
|
||||
$e_remote = null;
|
||||
} catch (Exception $ex) {
|
||||
$e_remote = pht('Invalid');
|
||||
$errors[] = $ex->getMessage();
|
||||
}
|
||||
} else {
|
||||
$e_remote = pht('Required');
|
||||
$errors[] = pht('You must provide a remote URI.');
|
||||
}
|
||||
|
||||
$v_credentials = $request->getStr('credential');
|
||||
if ($v_credentials) {
|
||||
$phids = mpull($credentials, null, 'getPHID');
|
||||
if (empty($phids[$v_credentials])) {
|
||||
$e_credentials = pht('Invalid');
|
||||
$errors[] = pht(
|
||||
'You do not have permission to use those credentials.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$mirror
|
||||
->setRemoteURI($v_remote)
|
||||
->setCredentialPHID($v_credentials)
|
||||
->save();
|
||||
return id(new AphrontReloadResponse())->setURI($edit_uri);
|
||||
}
|
||||
}
|
||||
|
||||
$form_errors = null;
|
||||
if ($errors) {
|
||||
$form_errors = id(new PHUIInfoView())
|
||||
->setErrors($errors);
|
||||
}
|
||||
|
||||
if ($is_new) {
|
||||
$title = pht('Create Mirror');
|
||||
$submit = pht('Create Mirror');
|
||||
} else {
|
||||
$title = pht('Edit Mirror');
|
||||
$submit = pht('Save Changes');
|
||||
}
|
||||
|
||||
$form = id(new PHUIFormLayoutView())
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Remote URI'))
|
||||
->setName('remoteURI')
|
||||
->setValue($v_remote)
|
||||
->setError($e_remote))
|
||||
->appendChild(
|
||||
id(new PassphraseCredentialControl())
|
||||
->setLabel(pht('Credentials'))
|
||||
->setName('credential')
|
||||
->setAllowNull(true)
|
||||
->setValue($v_credentials)
|
||||
->setError($e_credentials)
|
||||
->setOptions($credentials));
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle($title)
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->appendChild($form_errors)
|
||||
->appendChild($form)
|
||||
->addSubmitButton($submit)
|
||||
->addCancelButton($edit_uri);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -248,21 +248,14 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
private function buildCurtain(PhabricatorRepository $repository) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$edit_uri = $repository->getPathURI('edit/');
|
||||
$edit_uri = $repository->getPathURI('manage/');
|
||||
$curtain = $this->newCurtainView($repository);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Repository'))
|
||||
->setIcon('fa-pencil')
|
||||
->setHref($edit_uri)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setDisabled(!$can_edit));
|
||||
->setName(pht('Manage Repository'))
|
||||
->setIcon('fa-cogs')
|
||||
->setHref($edit_uri));
|
||||
|
||||
if ($repository->isHosted()) {
|
||||
$push_uri = $this->getApplicationURI(
|
||||
|
@ -301,56 +294,27 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
$view = id(new PHUIPropertyListView())
|
||||
->setUser($viewer);
|
||||
|
||||
if ($repository->isHosted()) {
|
||||
$ssh_uri = $repository->getSSHCloneURIObject();
|
||||
if ($ssh_uri) {
|
||||
$clone_uri = $this->renderCloneCommand(
|
||||
$repository,
|
||||
$ssh_uri,
|
||||
$repository->getServeOverSSH(),
|
||||
'/settings/panel/ssh/');
|
||||
$display_never = PhabricatorRepositoryURI::DISPLAY_NEVER;
|
||||
|
||||
$view->addProperty(
|
||||
$repository->isSVN()
|
||||
? pht('Checkout (SSH)')
|
||||
: pht('Clone (SSH)'),
|
||||
$clone_uri);
|
||||
$uris = $repository->getURIs();
|
||||
foreach ($uris as $uri) {
|
||||
if ($uri->getIsDisabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$http_uri = $repository->getHTTPCloneURIObject();
|
||||
if ($http_uri) {
|
||||
$clone_uri = $this->renderCloneCommand(
|
||||
$repository,
|
||||
$http_uri,
|
||||
$repository->getServeOverHTTP(),
|
||||
PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')
|
||||
? '/settings/panel/vcspassword/'
|
||||
: null);
|
||||
if ($uri->getEffectiveDisplayType() == $display_never) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$view->addProperty(
|
||||
$repository->isSVN()
|
||||
? pht('Checkout (HTTP)')
|
||||
: pht('Clone (HTTP)'),
|
||||
$clone_uri);
|
||||
}
|
||||
} else {
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$view->addProperty(
|
||||
pht('Clone'),
|
||||
$this->renderCloneCommand(
|
||||
$repository,
|
||||
$repository->getPublicCloneURI()));
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$view->addProperty(
|
||||
pht('Checkout'),
|
||||
$this->renderCloneCommand(
|
||||
$repository,
|
||||
$repository->getPublicCloneURI()));
|
||||
break;
|
||||
if ($repository->isSVN()) {
|
||||
$label = pht('Checkout');
|
||||
} else {
|
||||
$label = pht('Clone');
|
||||
}
|
||||
|
||||
$view->addProperty(
|
||||
$label,
|
||||
$this->renderCloneURI($repository, $uri));
|
||||
}
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
|
@ -701,80 +665,27 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
);
|
||||
}
|
||||
|
||||
private function renderCloneCommand(
|
||||
private function renderCloneURI(
|
||||
PhabricatorRepository $repository,
|
||||
$uri,
|
||||
$serve_mode = null,
|
||||
$manage_uri = null) {
|
||||
PhabricatorRepositoryURI $uri) {
|
||||
|
||||
require_celerity_resource('diffusion-icons-css');
|
||||
|
||||
Javelin::initBehavior('select-on-click');
|
||||
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$command = csprintf(
|
||||
'git clone %R',
|
||||
$uri);
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$command = csprintf(
|
||||
'hg clone %R',
|
||||
$uri);
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
if ($repository->isHosted()) {
|
||||
$command = csprintf(
|
||||
'svn checkout %R %R',
|
||||
$uri,
|
||||
$repository->getCloneName());
|
||||
} else {
|
||||
$command = csprintf(
|
||||
'svn checkout %R',
|
||||
$uri);
|
||||
}
|
||||
break;
|
||||
if ($repository->isSVN()) {
|
||||
$display = csprintf(
|
||||
'svn checkout %R %R',
|
||||
(string)$uri->getDisplayURI(),
|
||||
$repository->getCloneName());
|
||||
} else {
|
||||
$display = csprintf('%R', (string)$uri->getDisplayURI());
|
||||
}
|
||||
|
||||
$input = javelin_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'text',
|
||||
'value' => (string)$command,
|
||||
'class' => 'diffusion-clone-uri',
|
||||
'sigil' => 'select-on-click',
|
||||
'readonly' => 'true',
|
||||
));
|
||||
$display = (string)$display;
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$extras = array();
|
||||
if ($serve_mode) {
|
||||
if ($serve_mode === PhabricatorRepository::SERVE_READONLY) {
|
||||
$extras[] = pht('(Read Only)');
|
||||
}
|
||||
}
|
||||
|
||||
if ($manage_uri) {
|
||||
if ($this->getRequest()->getUser()->isLoggedIn()) {
|
||||
$extras[] = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $manage_uri,
|
||||
),
|
||||
pht('Manage Credentials'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($extras) {
|
||||
$extras = phutil_implode_html(' ', $extras);
|
||||
$extras = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'diffusion-clone-extras',
|
||||
),
|
||||
$extras);
|
||||
}
|
||||
|
||||
return array($input, $extras);
|
||||
return id(new DiffusionCloneURIView())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->setRepositoryURI($uri)
|
||||
->setDisplayURI($display);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,848 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryCreateController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
private $edit;
|
||||
private $repository;
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
$this->edit = $request->getURIData('edit');
|
||||
|
||||
// NOTE: We can end up here via either "Create Repository", or via
|
||||
// "Import Repository", or via "Edit Remote", or via "Edit Policies". In
|
||||
// the latter two cases, we show only a few of the pages.
|
||||
|
||||
$repository = null;
|
||||
$service = null;
|
||||
switch ($this->edit) {
|
||||
case 'remote':
|
||||
case 'policy':
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$repository = $this->getDiffusionRequest()->getRepository();
|
||||
|
||||
// Make sure we have CAN_EDIT.
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$this->setRepository($repository);
|
||||
|
||||
$cancel_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
break;
|
||||
case 'import':
|
||||
case 'create':
|
||||
$this->requireApplicationCapability(
|
||||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
|
||||
// Pick a random open service to allocate this repository on, if any
|
||||
// exist. If there are no services, we aren't in cluster mode and
|
||||
// will allocate locally. If there are services but none permit
|
||||
// allocations, we fail.
|
||||
$services = id(new AlmanacServiceQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withServiceTypes(
|
||||
array(
|
||||
AlmanacClusterRepositoryServiceType::SERVICETYPE,
|
||||
))
|
||||
->needProperties(true)
|
||||
->execute();
|
||||
if ($services) {
|
||||
// Filter out services which do not permit new allocations.
|
||||
foreach ($services as $key => $possible_service) {
|
||||
if ($possible_service->getAlmanacPropertyValue('closed')) {
|
||||
unset($services[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$services) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This install is configured in cluster mode, but all '.
|
||||
'available repository cluster services are closed to new '.
|
||||
'allocations. At least one service must be open to allow '.
|
||||
'new allocations to take place.'));
|
||||
}
|
||||
|
||||
shuffle($services);
|
||||
$service = head($services);
|
||||
}
|
||||
|
||||
$cancel_uri = $this->getApplicationURI('new/');
|
||||
break;
|
||||
default:
|
||||
throw new Exception(pht('Invalid edit operation!'));
|
||||
}
|
||||
|
||||
$form = id(new PHUIPagedFormView())
|
||||
->setUser($viewer)
|
||||
->setCancelURI($cancel_uri);
|
||||
|
||||
switch ($this->edit) {
|
||||
case 'remote':
|
||||
$title = pht('Edit Remote');
|
||||
$form
|
||||
->addPage('remote-uri', $this->buildRemoteURIPage())
|
||||
->addPage('auth', $this->buildAuthPage());
|
||||
break;
|
||||
case 'policy':
|
||||
$title = pht('Edit Policies');
|
||||
$form
|
||||
->addPage('policy', $this->buildPolicyPage());
|
||||
break;
|
||||
case 'create':
|
||||
$title = pht('Create Repository');
|
||||
$form
|
||||
->addPage('vcs', $this->buildVCSPage())
|
||||
->addPage('name', $this->buildNamePage())
|
||||
->addPage('policy', $this->buildPolicyPage())
|
||||
->addPage('done', $this->buildDonePage());
|
||||
break;
|
||||
case 'import':
|
||||
$title = pht('Import Repository');
|
||||
$form
|
||||
->addPage('vcs', $this->buildVCSPage())
|
||||
->addPage('name', $this->buildNamePage())
|
||||
->addPage('remote-uri', $this->buildRemoteURIPage())
|
||||
->addPage('auth', $this->buildAuthPage())
|
||||
->addPage('policy', $this->buildPolicyPage())
|
||||
->addPage('done', $this->buildDonePage());
|
||||
break;
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$form->readFromRequest($request);
|
||||
if ($form->isComplete()) {
|
||||
|
||||
$is_create = ($this->edit === 'import' || $this->edit === 'create');
|
||||
$is_auth = ($this->edit == 'import' || $this->edit == 'remote');
|
||||
$is_policy = ($this->edit != 'remote');
|
||||
$is_init = ($this->edit == 'create');
|
||||
|
||||
if ($is_create) {
|
||||
$repository = PhabricatorRepository::initializeNewRepository(
|
||||
$viewer);
|
||||
}
|
||||
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
||||
$type_vcs = PhabricatorRepositoryTransaction::TYPE_VCS;
|
||||
$type_activate = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
|
||||
$type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
|
||||
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
|
||||
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
|
||||
$type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
|
||||
$type_credential = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
||||
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
$type_space = PhabricatorTransactions::TYPE_SPACE;
|
||||
$type_push = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
||||
$type_service = PhabricatorRepositoryTransaction::TYPE_SERVICE;
|
||||
|
||||
$xactions = array();
|
||||
|
||||
// If we're creating a new repository, set all this core stuff.
|
||||
if ($is_create) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_name)
|
||||
->setNewValue(
|
||||
$form->getPage('name')->getControl('name')->getValue());
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_vcs)
|
||||
->setNewValue(
|
||||
$form->getPage('vcs')->getControl('vcs')->getValue());
|
||||
|
||||
$activate = $form->getPage('done')
|
||||
->getControl('activate')->getValue();
|
||||
if ($activate == 'start') {
|
||||
$initial_status = PhabricatorRepository::STATUS_ACTIVE;
|
||||
} else {
|
||||
$initial_status = PhabricatorRepository::STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_activate)
|
||||
->setNewValue($initial_status);
|
||||
|
||||
if ($service) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_service)
|
||||
->setNewValue($service->getPHID());
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_init) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_hosting)
|
||||
->setNewValue(true);
|
||||
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
|
||||
if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) {
|
||||
if (PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')) {
|
||||
$v_http_mode = PhabricatorRepository::SERVE_READWRITE;
|
||||
} else {
|
||||
$v_http_mode = PhabricatorRepository::SERVE_OFF;
|
||||
}
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_http)
|
||||
->setNewValue($v_http_mode);
|
||||
}
|
||||
|
||||
if (PhabricatorEnv::getEnvConfig('diffusion.ssh-user')) {
|
||||
$v_ssh_mode = PhabricatorRepository::SERVE_READWRITE;
|
||||
} else {
|
||||
$v_ssh_mode = PhabricatorRepository::SERVE_OFF;
|
||||
}
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_ssh)
|
||||
->setNewValue($v_ssh_mode);
|
||||
}
|
||||
|
||||
if ($is_auth) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_remote_uri)
|
||||
->setNewValue(
|
||||
$form->getPage('remote-uri')->getControl('remoteURI')
|
||||
->getValue());
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_credential)
|
||||
->setNewValue(
|
||||
$form->getPage('auth')->getControl('credential')->getValue());
|
||||
}
|
||||
|
||||
if ($is_policy) {
|
||||
$policy_page = $form->getPage('policy');
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_view)
|
||||
->setNewValue($policy_page->getControl('viewPolicy')->getValue());
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_edit)
|
||||
->setNewValue($policy_page->getControl('editPolicy')->getValue());
|
||||
|
||||
if ($is_init || $repository->isHosted()) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_push)
|
||||
->setNewValue($policy_page->getControl('pushPolicy')->getValue());
|
||||
}
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_space)
|
||||
->setNewValue(
|
||||
$policy_page->getControl('viewPolicy')->getSpacePHID());
|
||||
}
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
$repo_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
return id(new AphrontRedirectResponse())->setURI($repo_uri);
|
||||
}
|
||||
} else {
|
||||
$dict = array();
|
||||
if ($repository) {
|
||||
$dict = array(
|
||||
'remoteURI' => $repository->getRemoteURI(),
|
||||
'credential' => $repository->getCredentialPHID(),
|
||||
'viewPolicy' => $repository->getViewPolicy(),
|
||||
'editPolicy' => $repository->getEditPolicy(),
|
||||
'pushPolicy' => $repository->getPushPolicy(),
|
||||
'spacePHID' => $repository->getSpacePHID(),
|
||||
);
|
||||
}
|
||||
$form->readFromObject($dict);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: VCS Type )----------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildVCSPage() {
|
||||
|
||||
$is_import = ($this->edit == 'import');
|
||||
|
||||
if ($is_import) {
|
||||
$git_str = pht(
|
||||
'Import a Git repository (for example, a repository hosted '.
|
||||
'on GitHub).');
|
||||
$hg_str = pht(
|
||||
'Import a Mercurial repository (for example, a repository '.
|
||||
'hosted on Bitbucket).');
|
||||
$svn_str = pht('Import a Subversion repository.');
|
||||
} else {
|
||||
$git_str = pht('Create a new, empty Git repository.');
|
||||
$hg_str = pht('Create a new, empty Mercurial repository.');
|
||||
$svn_str = pht('Create a new, empty Subversion repository.');
|
||||
}
|
||||
|
||||
$control = id(new AphrontFormRadioButtonControl())
|
||||
->setName('vcs')
|
||||
->setLabel(pht('Type'))
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
|
||||
pht('Git'),
|
||||
$git_str)
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
|
||||
pht('Mercurial'),
|
||||
$hg_str)
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
|
||||
pht('Subversion'),
|
||||
$svn_str);
|
||||
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Repository Type'))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setValidateFormPageCallback(array($this, 'validateVCSPage'))
|
||||
->addControl($control);
|
||||
}
|
||||
|
||||
public function validateVCSPage(PHUIFormPageView $page) {
|
||||
$valid = array(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => true,
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => true,
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => true,
|
||||
);
|
||||
|
||||
$c_vcs = $page->getControl('vcs');
|
||||
$v_vcs = $c_vcs->getValue();
|
||||
if (!$v_vcs) {
|
||||
$c_vcs->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must select a version control system.'));
|
||||
} else if (empty($valid[$v_vcs])) {
|
||||
$c_vcs->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht('You must select a valid version control system.'));
|
||||
}
|
||||
|
||||
return $c_vcs->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: Name )--------------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildNamePage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setPageName(pht('Repository Name and Location'))
|
||||
->setValidateFormPageCallback(array($this, 'validateNamePage'))
|
||||
->addRemarkupInstructions(
|
||||
pht(
|
||||
'**Choose a human-readable name for this repository**, like '.
|
||||
'"CompanyName Mobile App" or "CompanyName Backend Server". You '.
|
||||
'can change this later.'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('name')
|
||||
->setLabel(pht('Name')));
|
||||
}
|
||||
|
||||
public function validateNamePage(PHUIFormPageView $page) {
|
||||
$c_name = $page->getControl('name');
|
||||
$v_name = $c_name->getValue();
|
||||
if (!strlen($v_name)) {
|
||||
$c_name->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must choose a name for this repository.'));
|
||||
}
|
||||
|
||||
return $c_name->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: Remote URI )--------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildRemoteURIPage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setPageName(pht('Repository Remote URI'))
|
||||
->setValidateFormPageCallback(array($this, 'validateRemoteURIPage'))
|
||||
->setAdjustFormPageCallback(array($this, 'adjustRemoteURIPage'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('remoteURI'));
|
||||
}
|
||||
|
||||
public function adjustRemoteURIPage(PHUIFormPageView $page) {
|
||||
$form = $page->getForm();
|
||||
|
||||
$is_git = false;
|
||||
$is_svn = false;
|
||||
$is_mercurial = false;
|
||||
|
||||
if ($this->getRepository()) {
|
||||
$vcs = $this->getRepository()->getVersionControlSystem();
|
||||
} else {
|
||||
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
|
||||
}
|
||||
|
||||
switch ($vcs) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$is_git = true;
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$is_svn = true;
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$is_mercurial = true;
|
||||
break;
|
||||
default:
|
||||
throw new Exception(pht('Unsupported VCS!'));
|
||||
}
|
||||
|
||||
$has_local = ($is_git || $is_mercurial);
|
||||
if ($is_git) {
|
||||
$uri_label = pht('Remote URI');
|
||||
$instructions = pht(
|
||||
'Enter the URI to clone this Git repository from. It should usually '.
|
||||
'look like one of these examples:'.
|
||||
"\n\n".
|
||||
"| Example Git Remote URIs |\n".
|
||||
"| ----------------------- |\n".
|
||||
"| `git@github.com:example/example.git` |\n".
|
||||
"| `ssh://user@host.com/git/example.git` |\n".
|
||||
"| `https://example.com/repository.git` |\n");
|
||||
} else if ($is_mercurial) {
|
||||
$uri_label = pht('Remote URI');
|
||||
$instructions = pht(
|
||||
'Enter the URI to clone this Mercurial repository from. It should '.
|
||||
'usually look like one of these examples:'.
|
||||
"\n\n".
|
||||
"| Example Mercurial Remote URIs |\n".
|
||||
"| ----------------------- |\n".
|
||||
"| `ssh://hg@bitbucket.org/example/repository` |\n".
|
||||
"| `https://bitbucket.org/example/repository` |\n");
|
||||
} else if ($is_svn) {
|
||||
$uri_label = pht('Repository Root');
|
||||
$instructions = pht(
|
||||
'Enter the **Repository Root** for this Subversion repository. '.
|
||||
'You can figure this out by running `svn info` in a working copy '.
|
||||
'and looking at the value in the `Repository Root` field. It '.
|
||||
'should be a URI and will usually look like these:'.
|
||||
"\n\n".
|
||||
"| Example Subversion Repository Root URIs |\n".
|
||||
"| ------------------------------ |\n".
|
||||
"| `http://svn.example.org/svnroot/` |\n".
|
||||
"| `svn+ssh://svn.example.com/svnroot/` |\n".
|
||||
"| `svn://svn.example.net/svnroot/` |\n".
|
||||
"\n\n".
|
||||
"You **MUST** specify the root of the repository, not a ".
|
||||
"subdirectory. (If you want to import only part of a Subversion ".
|
||||
"repository, use the //Import Only// option at the end of this ".
|
||||
"workflow.)");
|
||||
} else {
|
||||
throw new Exception(pht('Unsupported VCS!'));
|
||||
}
|
||||
|
||||
$page->addRemarkupInstructions($instructions, 'remoteURI');
|
||||
$page->getControl('remoteURI')->setLabel($uri_label);
|
||||
}
|
||||
|
||||
public function validateRemoteURIPage(PHUIFormPageView $page) {
|
||||
$c_remote = $page->getControl('remoteURI');
|
||||
$v_remote = $c_remote->getValue();
|
||||
|
||||
if (!strlen($v_remote)) {
|
||||
$c_remote->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must specify a URI.'));
|
||||
} else {
|
||||
try {
|
||||
PhabricatorRepository::assertValidRemoteURI($v_remote);
|
||||
} catch (Exception $ex) {
|
||||
$c_remote->setError(pht('Invalid'));
|
||||
$page->addPageError($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $c_remote->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: Authentication )----------------------------------------------- */
|
||||
|
||||
|
||||
public function buildAuthPage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Authentication'))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setAdjustFormPageCallback(array($this, 'adjustAuthPage'))
|
||||
->addControl(
|
||||
id(new PassphraseCredentialControl())
|
||||
->setName('credential'));
|
||||
}
|
||||
|
||||
|
||||
public function adjustAuthPage($page) {
|
||||
$form = $page->getForm();
|
||||
|
||||
if ($this->getRepository()) {
|
||||
$vcs = $this->getRepository()->getVersionControlSystem();
|
||||
} else {
|
||||
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
|
||||
}
|
||||
|
||||
$remote_uri = $form->getPage('remote-uri')
|
||||
->getControl('remoteURI')
|
||||
->getValue();
|
||||
|
||||
$proto = PhabricatorRepository::getRemoteURIProtocol($remote_uri);
|
||||
$remote_user = $this->getRemoteURIUser($remote_uri);
|
||||
|
||||
$c_credential = $page->getControl('credential');
|
||||
$c_credential->setDefaultUsername($remote_user);
|
||||
|
||||
if ($this->isSSHProtocol($proto)) {
|
||||
$c_credential->setLabel(pht('SSH Key'));
|
||||
$c_credential->setCredentialType(
|
||||
PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE);
|
||||
$provides_type = PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
|
||||
|
||||
$page->addRemarkupInstructions(
|
||||
pht(
|
||||
'Choose or add the SSH credentials to use to connect to the '.
|
||||
'repository hosted at:'.
|
||||
"\n\n".
|
||||
" lang=text\n".
|
||||
" %s",
|
||||
$remote_uri),
|
||||
'credential');
|
||||
} else if ($this->isUsernamePasswordProtocol($proto)) {
|
||||
$c_credential->setLabel(pht('Password'));
|
||||
$c_credential->setAllowNull(true);
|
||||
$c_credential->setCredentialType(
|
||||
PassphrasePasswordCredentialType::CREDENTIAL_TYPE);
|
||||
$provides_type = PassphrasePasswordCredentialType::PROVIDES_TYPE;
|
||||
|
||||
$page->addRemarkupInstructions(
|
||||
pht(
|
||||
'Choose the username and password used to connect to the '.
|
||||
'repository hosted at:'.
|
||||
"\n\n".
|
||||
" lang=text\n".
|
||||
" %s".
|
||||
"\n\n".
|
||||
"If this repository does not require a username or password, ".
|
||||
"you can continue to the next step.",
|
||||
$remote_uri),
|
||||
'credential');
|
||||
} else {
|
||||
throw new Exception(pht('Unknown URI protocol!'));
|
||||
}
|
||||
|
||||
if ($provides_type) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$options = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withIsDestroyed(false)
|
||||
->withProvidesTypes(array($provides_type))
|
||||
->execute();
|
||||
|
||||
$c_credential->setOptions($options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function validateAuthPage(PHUIFormPageView $page) {
|
||||
$form = $page->getForm();
|
||||
$remote_uri = $form->getPage('remote')->getControl('remoteURI')->getValue();
|
||||
$proto = $this->getRemoteURIProtocol($remote_uri);
|
||||
|
||||
$c_credential = $page->getControl('credential');
|
||||
$v_credential = $c_credential->getValue();
|
||||
|
||||
// NOTE: We're using the omnipotent user here because the viewer might be
|
||||
// editing a repository they're allowed to edit which uses a credential they
|
||||
// are not allowed to see. This is fine, as long as they don't change it.
|
||||
$credential = id(new PassphraseCredentialQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($v_credential))
|
||||
->executeOne();
|
||||
|
||||
if ($this->isSSHProtocol($proto)) {
|
||||
if (!$credential) {
|
||||
$c_credential->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must choose an SSH credential to connect over SSH.'));
|
||||
}
|
||||
|
||||
$ssh_type = PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
|
||||
if ($credential->getProvidesType() !== $ssh_type) {
|
||||
$c_credential->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'You must choose an SSH credential, not some other type '.
|
||||
'of credential.'));
|
||||
}
|
||||
|
||||
} else if ($this->isUsernamePasswordProtocol($proto)) {
|
||||
if ($credential) {
|
||||
$password_type = PassphrasePasswordCredentialType::PROVIDES_TYPE;
|
||||
if ($credential->getProvidesType() !== $password_type) {
|
||||
$c_credential->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'You must choose a username/password credential, not some other '.
|
||||
'type of credential.'));
|
||||
}
|
||||
}
|
||||
|
||||
return $c_credential->isValid();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: Policy )------------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildPolicyPage() {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
if ($this->getRepository()) {
|
||||
$repository = $this->getRepository();
|
||||
} else {
|
||||
$repository = PhabricatorRepository::initializeNewRepository($viewer);
|
||||
}
|
||||
|
||||
$policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($viewer)
|
||||
->setObject($repository)
|
||||
->execute();
|
||||
|
||||
$view_policy = id(new AphrontFormPolicyControl())
|
||||
->setUser($viewer)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||
->setPolicyObject($repository)
|
||||
->setPolicies($policies)
|
||||
->setName('viewPolicy');
|
||||
|
||||
$edit_policy = id(new AphrontFormPolicyControl())
|
||||
->setUser($viewer)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||
->setPolicyObject($repository)
|
||||
->setPolicies($policies)
|
||||
->setName('editPolicy');
|
||||
|
||||
$push_policy = id(new AphrontFormPolicyControl())
|
||||
->setUser($viewer)
|
||||
->setCapability(DiffusionPushCapability::CAPABILITY)
|
||||
->setPolicyObject($repository)
|
||||
->setPolicies($policies)
|
||||
->setName('pushPolicy');
|
||||
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Policies'))
|
||||
->setValidateFormPageCallback(array($this, 'validatePolicyPage'))
|
||||
->setAdjustFormPageCallback(array($this, 'adjustPolicyPage'))
|
||||
->setUser($viewer)
|
||||
->addRemarkupInstructions(
|
||||
pht('Select access policies for this repository.'))
|
||||
->addControl($view_policy)
|
||||
->addControl($edit_policy)
|
||||
->addControl($push_policy);
|
||||
}
|
||||
|
||||
public function adjustPolicyPage(PHUIFormPageView $page) {
|
||||
if ($this->getRepository()) {
|
||||
$repository = $this->getRepository();
|
||||
$show_push = $repository->isHosted();
|
||||
} else {
|
||||
$show_push = ($this->edit == 'create');
|
||||
}
|
||||
|
||||
if (!$show_push) {
|
||||
$c_push = $page->getControl('pushPolicy');
|
||||
$c_push->setHidden(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function validatePolicyPage(PHUIFormPageView $page) {
|
||||
$form = $page->getForm();
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$c_view = $page->getControl('viewPolicy');
|
||||
$c_edit = $page->getControl('editPolicy');
|
||||
$c_push = $page->getControl('pushPolicy');
|
||||
$v_view = $c_view->getValue();
|
||||
$v_edit = $c_edit->getValue();
|
||||
$v_push = $c_push->getValue();
|
||||
|
||||
if ($this->getRepository()) {
|
||||
$repository = $this->getRepository();
|
||||
} else {
|
||||
$repository = PhabricatorRepository::initializeNewRepository($viewer);
|
||||
}
|
||||
|
||||
$proxy = clone $repository;
|
||||
$proxy->setViewPolicy($v_view);
|
||||
$proxy->setEditPolicy($v_edit);
|
||||
|
||||
$can_view = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$proxy,
|
||||
PhabricatorPolicyCapability::CAN_VIEW);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$proxy,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
if (!$can_view) {
|
||||
$c_view->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'You can not use the selected policy, because you would be unable '.
|
||||
'to see the repository.'));
|
||||
}
|
||||
|
||||
if (!$can_edit) {
|
||||
$c_edit->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'You can not use the selected edit policy, because you would be '.
|
||||
'unable to edit the repository.'));
|
||||
}
|
||||
|
||||
return $c_view->isValid() &&
|
||||
$c_edit->isValid();
|
||||
}
|
||||
|
||||
/* -( Page: Done )--------------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildDonePage() {
|
||||
|
||||
$is_create = ($this->edit == 'create');
|
||||
if ($is_create) {
|
||||
$now_label = pht('Create Repository Now');
|
||||
$now_caption = pht(
|
||||
'Create the repository right away. This will create the repository '.
|
||||
'using default settings.');
|
||||
|
||||
$wait_label = pht('Configure More Options First');
|
||||
$wait_caption = pht(
|
||||
'Configure more options before creating the repository. '.
|
||||
'This will let you fine-tune settings. You can create the repository '.
|
||||
'whenever you are ready.');
|
||||
} else {
|
||||
$now_label = pht('Start Import Now');
|
||||
$now_caption = pht(
|
||||
'Start importing the repository right away. This will import '.
|
||||
'the entire repository using default settings.');
|
||||
|
||||
$wait_label = pht('Configure More Options First');
|
||||
$wait_caption = pht(
|
||||
'Configure more options before beginning the repository '.
|
||||
'import. This will let you fine-tune settings. You can '.
|
||||
'start the import whenever you are ready.');
|
||||
}
|
||||
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Repository Ready!'))
|
||||
->setValidateFormPageCallback(array($this, 'validateDonePage'))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->addControl(
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('activate')
|
||||
->setLabel(pht('Start Now'))
|
||||
->addButton(
|
||||
'start',
|
||||
$now_label,
|
||||
$now_caption)
|
||||
->addButton(
|
||||
'wait',
|
||||
$wait_label,
|
||||
$wait_caption));
|
||||
}
|
||||
|
||||
public function validateDonePage(PHUIFormPageView $page) {
|
||||
$c_activate = $page->getControl('activate');
|
||||
$v_activate = $c_activate->getValue();
|
||||
|
||||
if ($v_activate != 'start' && $v_activate != 'wait') {
|
||||
$c_activate->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('Make a choice about repository activation.'));
|
||||
}
|
||||
|
||||
return $c_activate->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Internal )----------------------------------------------------------- */
|
||||
|
||||
private function getRemoteURIUser($raw_uri) {
|
||||
$uri = new PhutilURI($raw_uri);
|
||||
if ($uri->getUser()) {
|
||||
return $uri->getUser();
|
||||
}
|
||||
|
||||
$git_uri = new PhutilGitURI($raw_uri);
|
||||
if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) {
|
||||
return $git_uri->getUser();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function isSSHProtocol($proto) {
|
||||
return ($proto == 'git' || $proto == 'ssh' || $proto == 'svn+ssh');
|
||||
}
|
||||
|
||||
private function isUsernamePasswordProtocol($proto) {
|
||||
return ($proto == 'http' || $proto == 'https' || $proto == 'svn');
|
||||
}
|
||||
|
||||
private function setRepository(PhabricatorRepository $repository) {
|
||||
$this->repository = $repository;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getRepository() {
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditActionsController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
// NOTE: We're inverting these here, because the storage is silly.
|
||||
$v_notify = !$repository->getHumanReadableDetail('herald-disabled');
|
||||
$v_autoclose = !$repository->getHumanReadableDetail('disable-autoclose');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_notify = $request->getBool('notify');
|
||||
$v_autoclose = $request->getBool('autoclose');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_notify = PhabricatorRepositoryTransaction::TYPE_NOTIFY;
|
||||
$type_autoclose = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_notify)
|
||||
->setNewValue($v_notify);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_autoclose)
|
||||
->setNewValue($v_autoclose);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
$content = array();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Actions'));
|
||||
|
||||
$title = pht('Edit Actions (%s)', $repository->getName());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($viewer)
|
||||
->setObject($repository)
|
||||
->execute();
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
"Normally, Phabricator publishes notifications when it discovers ".
|
||||
"new commits. You can disable publishing for this repository by ".
|
||||
"turning off **Notify/Publish**. This will disable notifications, ".
|
||||
"feed, and Herald (including audits and build plans) for this ".
|
||||
"repository.\n\n".
|
||||
"When Phabricator discovers a new commit, it can automatically ".
|
||||
"close associated revisions and tasks. If you don't want ".
|
||||
"Phabricator to close objects when it discovers new commits in ".
|
||||
"this repository, you can disable **Autoclose**."))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('notify')
|
||||
->setLabel(pht('Notify/Publish'))
|
||||
->setValue((int)$v_notify)
|
||||
->setOptions(
|
||||
array(
|
||||
1 => pht('Enable Notifications, Feed and Herald'),
|
||||
0 => pht('Disable Notifications, Feed and Herald'),
|
||||
)))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('autoclose')
|
||||
->setLabel(pht('Autoclose'))
|
||||
->setValue((int)$v_autoclose)
|
||||
->setOptions(
|
||||
array(
|
||||
1 => pht('Enable Autoclose'),
|
||||
0 => pht('Disable Autoclose'),
|
||||
)))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Actions'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Actions'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditActivateController
|
||||
extends DiffusionRepositoryEditController {
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
|
@ -13,7 +13,9 @@ final class DiffusionRepositoryEditActivateController
|
|||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$panel_uri = id(new DiffusionRepositoryBasicsManagementPanel())
|
||||
->setRepository($repository)
|
||||
->getPanelURI();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
if (!$repository->isTracked()) {
|
||||
|
@ -33,24 +35,44 @@ final class DiffusionRepositoryEditActivateController
|
|||
->setActor($viewer)
|
||||
->applyTransactions($repository, array($xaction));
|
||||
|
||||
return id(new AphrontReloadResponse())->setURI($edit_uri);
|
||||
return id(new AphrontReloadResponse())->setURI($panel_uri);
|
||||
}
|
||||
|
||||
if ($repository->isTracked()) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Deactivate Repository?'))
|
||||
->appendChild(
|
||||
pht('Deactivate this repository?'))
|
||||
->addSubmitButton(pht('Deactivate Repository'))
|
||||
->addCancelButton($edit_uri);
|
||||
$title = pht('Deactivate Repository');
|
||||
$body = pht(
|
||||
'If you deactivate this repository, it will no longer be updated. '.
|
||||
'Observation and mirroring will cease, and pushing and pulling will '.
|
||||
'be disabled. You can reactivate the repository later.');
|
||||
$submit = pht('Deactivate Repository');
|
||||
} else {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Activate Repository?'))
|
||||
->appendChild(
|
||||
pht('Activate this repository?'))
|
||||
->addSubmitButton(pht('Activate Repository'))
|
||||
->addCancelButton($edit_uri);
|
||||
$title = pht('Activate Repository');
|
||||
|
||||
$is_new = $repository->isNewlyInitialized();
|
||||
if ($is_new) {
|
||||
if ($repository->isHosted()) {
|
||||
$body = pht(
|
||||
'This repository will become a new hosted repository. '.
|
||||
'It will begin serving read and write traffic.');
|
||||
} else {
|
||||
$body = pht(
|
||||
'This repository will observe an existing remote repository. '.
|
||||
'It will begin fetching changes from the remote.');
|
||||
}
|
||||
} else {
|
||||
$body = pht(
|
||||
'This repository will resume updates, observation, mirroring, '.
|
||||
'and serving any configured read and write traffic.');
|
||||
}
|
||||
|
||||
$submit = pht('Activate Repository');
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle($title)
|
||||
->appendChild($body)
|
||||
->addSubmitButton($submit)
|
||||
->addCancelButton($panel_uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditAutomationController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
if (!$repository->supportsAutomation()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_blueprints = $repository->getHumanReadableDetail(
|
||||
'automation.blueprintPHIDs');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_blueprints = $request->getArr('blueprintPHIDs');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_blueprints =
|
||||
PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_blueprints)
|
||||
->setNewValue($v_blueprints);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Automation'));
|
||||
|
||||
$title = pht('Edit %s', $repository->getName());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
"Configure **Repository Automation** to allow Phabricator to ".
|
||||
"write to this repository.".
|
||||
"\n\n".
|
||||
"IMPORTANT: This feature is new, experimental, and not supported. ".
|
||||
"Use it at your own risk."))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Use Blueprints'))
|
||||
->setName('blueprintPHIDs')
|
||||
->setValue($v_blueprints)
|
||||
->setDatasource(new DrydockBlueprintDatasource()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Automation'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditBasicController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $request->getUser();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_name = $repository->getName();
|
||||
$v_desc = $repository->getDetail('description');
|
||||
$v_slug = $repository->getRepositorySlug();
|
||||
$v_callsign = $repository->getCallsign();
|
||||
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$repository->getPHID(),
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||
$e_name = true;
|
||||
$e_slug = null;
|
||||
$e_callsign = null;
|
||||
$errors = array();
|
||||
|
||||
$validation_exception = null;
|
||||
if ($request->isFormPost()) {
|
||||
$v_name = $request->getStr('name');
|
||||
$v_desc = $request->getStr('description');
|
||||
$v_projects = $request->getArr('projectPHIDs');
|
||||
$v_slug = $request->getStr('slug');
|
||||
$v_callsign = $request->getStr('callsign');
|
||||
|
||||
if (!strlen($v_name)) {
|
||||
$e_name = pht('Required');
|
||||
$errors[] = pht('Repository name is required.');
|
||||
} else {
|
||||
$e_name = null;
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
||||
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
||||
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
||||
$type_slug = PhabricatorRepositoryTransaction::TYPE_SLUG;
|
||||
$type_callsign = PhabricatorRepositoryTransaction::TYPE_CALLSIGN;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_name)
|
||||
->setNewValue($v_name);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_desc)
|
||||
->setNewValue($v_desc);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_slug)
|
||||
->setNewValue($v_slug);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_callsign)
|
||||
->setNewValue($v_callsign);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_edge)
|
||||
->setMetadataValue(
|
||||
'edge:type',
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
|
||||
->setNewValue(
|
||||
array(
|
||||
'=' => array_fuse($v_projects),
|
||||
));
|
||||
|
||||
$editor = id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer);
|
||||
|
||||
try {
|
||||
$editor->applyTransactions($repository, $xactions);
|
||||
|
||||
// The preferred edit URI may have changed if the callsign or slug
|
||||
// were adjusted, so grab a fresh copy.
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$validation_exception = $ex;
|
||||
|
||||
$e_slug = $ex->getShortMessage($type_slug);
|
||||
$e_callsign = $ex->getShortMessage($type_callsign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Basics'));
|
||||
|
||||
$title = pht('Edit %s', $repository->getName());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setValue($v_name)
|
||||
->setError($e_name))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('slug')
|
||||
->setLabel(pht('Short Name'))
|
||||
->setValue($v_slug)
|
||||
->setError($e_slug))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('callsign')
|
||||
->setLabel(pht('Callsign'))
|
||||
->setValue($v_callsign)
|
||||
->setError($e_callsign))
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setUser($viewer)
|
||||
->setName('description')
|
||||
->setLabel(pht('Description'))
|
||||
->setValue($v_desc))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorProjectDatasource())
|
||||
->setName('projectPHIDs')
|
||||
->setLabel(pht('Projects'))
|
||||
->setValue($v_projects))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save'))
|
||||
->addCancelButton($edit_uri))
|
||||
->appendChild(id(new PHUIFormDividerControl()))
|
||||
->appendRemarkupInstructions($this->getReadmeInstructions());
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Basic Information'))
|
||||
->setValidationException($validation_exception)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form)
|
||||
->setFormErrors($errors);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function getReadmeInstructions() {
|
||||
return pht(<<<EOTEXT
|
||||
You can also create a `%s` file at the repository root (or in any
|
||||
subdirectory) to provide information about the repository. These formats are
|
||||
supported:
|
||||
|
||||
| File Name | Rendered As... |
|
||||
|-----------|-----------------|
|
||||
| `%s` | Plain Text |
|
||||
| `%s` | Plain Text |
|
||||
| `%s` | Remarkup |
|
||||
| `%s` | Remarkup |
|
||||
| `%s` | \xC2\xA1Fiesta! |
|
||||
EOTEXT
|
||||
,
|
||||
'README',
|
||||
'README',
|
||||
'README.txt',
|
||||
'README.remarkup',
|
||||
'README.md',
|
||||
'README.rainbow');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,248 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditBranchesController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$is_git = false;
|
||||
$is_hg = false;
|
||||
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$is_git = true;
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$is_hg = true;
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
throw new Exception(
|
||||
pht('Subversion does not support branches!'));
|
||||
default:
|
||||
throw new Exception(
|
||||
pht('Repository has unknown version control system!'));
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_default = $repository->getHumanReadableDetail('default-branch');
|
||||
$v_track = $repository->getDetail(
|
||||
'branch-filter',
|
||||
array());
|
||||
$v_track = array_keys($v_track);
|
||||
$v_autoclose = $repository->getDetail(
|
||||
'close-commits-filter',
|
||||
array());
|
||||
$v_autoclose = array_keys($v_autoclose);
|
||||
|
||||
$e_track = null;
|
||||
$e_autoclose = null;
|
||||
|
||||
$validation_exception = null;
|
||||
if ($request->isFormPost()) {
|
||||
$v_default = $request->getStr('default');
|
||||
|
||||
$v_track = $this->processBranches($request->getStr('track'));
|
||||
if (!$is_hg) {
|
||||
$v_autoclose = $this->processBranches($request->getStr('autoclose'));
|
||||
}
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_default = PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH;
|
||||
$type_track = PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY;
|
||||
$type_autoclose = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_default)
|
||||
->setNewValue($v_default);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_track)
|
||||
->setNewValue($v_track);
|
||||
|
||||
if (!$is_hg) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_autoclose)
|
||||
->setNewValue($v_autoclose);
|
||||
}
|
||||
|
||||
$editor = id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer);
|
||||
|
||||
try {
|
||||
$editor->applyTransactions($repository, $xactions);
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$validation_exception = $ex;
|
||||
|
||||
$e_track = $validation_exception->getShortMessage($type_track);
|
||||
$e_autoclose = $validation_exception->getShortMessage($type_autoclose);
|
||||
}
|
||||
}
|
||||
|
||||
$content = array();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Branches'));
|
||||
|
||||
$title = pht('Edit Branches (%s)', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($viewer)
|
||||
->setObject($repository)
|
||||
->execute();
|
||||
|
||||
$rows = array();
|
||||
$rows[] = array(
|
||||
array(
|
||||
'master',
|
||||
),
|
||||
pht('Select only master.'),
|
||||
);
|
||||
$rows[] = array(
|
||||
array(
|
||||
'master',
|
||||
'develop',
|
||||
'release',
|
||||
),
|
||||
pht('Select %s, %s, and %s.', 'master', 'develop', 'release'),
|
||||
);
|
||||
$rows[] = array(
|
||||
array(
|
||||
'master',
|
||||
'regexp(/^release-/)',
|
||||
),
|
||||
pht('Select master, and all branches which start with "%s".', 'release-'),
|
||||
);
|
||||
$rows[] = array(
|
||||
array(
|
||||
'regexp(/^(?!temp-)/)',
|
||||
),
|
||||
pht('Select all branches which do not start with "%s".', 'temp-'),
|
||||
);
|
||||
|
||||
foreach ($rows as $k => $row) {
|
||||
$rows[$k][0] = phutil_tag(
|
||||
'pre',
|
||||
array(),
|
||||
implode("\n", $row[0]));
|
||||
}
|
||||
|
||||
$example_table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Example'),
|
||||
pht('Effect'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
|
||||
$v_track = implode("\n", $v_track);
|
||||
$v_autoclose = implode("\n", $v_autoclose);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions(
|
||||
pht('You can choose a **Default Branch** for viewing this repository.'))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('default')
|
||||
->setLabel(pht('Default Branch'))
|
||||
->setValue($v_default))
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
'If you want to import only some branches into Diffusion, you can '.
|
||||
'list them in **Track Only**. Other branches will be ignored. If '.
|
||||
'you do not specify any branches, all branches are tracked.'));
|
||||
|
||||
if (!$is_hg) {
|
||||
$form->appendRemarkupInstructions(
|
||||
pht(
|
||||
'If you have **Autoclose** enabled for this repository, Phabricator '.
|
||||
'can close tasks and revisions when corresponding commits are '.
|
||||
'pushed to the repository. If you want to autoclose objects only '.
|
||||
'when commits appear on specific branches, you can list those '.
|
||||
'branches in **Autoclose Only**. By default, all tracked branches '.
|
||||
'will autoclose objects.'));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
'When specifying branches, you should enter one branch name per '.
|
||||
'line. You can use regular expressions to match branches by '.
|
||||
'wrapping an expression in `%s`. For example:',
|
||||
'regexp(...)'))
|
||||
->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setValue($example_table))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setName('track')
|
||||
->setLabel(pht('Track Only'))
|
||||
->setError($e_track)
|
||||
->setValue($v_track));
|
||||
|
||||
if (!$is_hg) {
|
||||
$form->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setName('autoclose')
|
||||
->setLabel(pht('Autoclose Only'))
|
||||
->setError($e_autoclose)
|
||||
->setValue($v_autoclose));
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Branches'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Branches'))
|
||||
->setValidationException($validation_exception)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function processBranches($string) {
|
||||
$lines = phutil_split_lines($string, $retain_endings = false);
|
||||
foreach ($lines as $key => $line) {
|
||||
$lines[$key] = trim($line);
|
||||
if (!strlen($lines[$key])) {
|
||||
unset($lines[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($lines);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +1,69 @@
|
|||
<?php
|
||||
|
||||
abstract class DiffusionRepositoryEditController
|
||||
extends DiffusionController {
|
||||
final class DiffusionRepositoryEditController
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
protected function buildApplicationCrumbs($is_main = false) {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$engine = id(new DiffusionRepositoryEditEngine())
|
||||
->setController($this);
|
||||
|
||||
if ($this->hasDiffusionRequest()) {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
$repo_uri = $repository->getURI();
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$id = $request->getURIData('id');
|
||||
if (!$id) {
|
||||
$this->requireApplicationCapability(
|
||||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
|
||||
$crumbs->addTextCrumb($repository->getDisplayname(), $repo_uri);
|
||||
|
||||
if ($is_main) {
|
||||
$crumbs->addTextCrumb(pht('Edit Repository'));
|
||||
} else {
|
||||
$crumbs->addTextCrumb(pht('Edit'), $edit_uri);
|
||||
$vcs = $request->getStr('vcs');
|
||||
$vcs_types = PhabricatorRepositoryType::getRepositoryTypeMap();
|
||||
if (empty($vcs_types[$vcs])) {
|
||||
return $this->buildVCSTypeResponse();
|
||||
}
|
||||
|
||||
$engine
|
||||
->addContextParameter('vcs', $vcs)
|
||||
->setVersionControlSystem($vcs);
|
||||
}
|
||||
|
||||
return $engine->buildResponse();
|
||||
}
|
||||
|
||||
private function buildVCSTypeResponse() {
|
||||
$vcs_types = PhabricatorRepositoryType::getRepositoryTypeMap();
|
||||
|
||||
$request = $this->getRequest();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Create Repository'));
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
return $crumbs;
|
||||
$title = pht('Choose Repository Type');
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Create Repository'))
|
||||
->setHeaderIcon('fa-plus-square');
|
||||
|
||||
$layout = id(new AphrontMultiColumnView())
|
||||
->setFluidLayout(true);
|
||||
|
||||
$create_uri = $request->getRequestURI();
|
||||
|
||||
foreach ($vcs_types as $vcs_key => $vcs_type) {
|
||||
$action = id(new PHUIActionPanelView())
|
||||
->setIcon(idx($vcs_type, 'icon'))
|
||||
->setHeader(idx($vcs_type, 'create.header'))
|
||||
->setHref($create_uri->alter('vcs', $vcs_key))
|
||||
->setSubheader(idx($vcs_type, 'create.subheader'));
|
||||
|
||||
$layout->addColumn($action);
|
||||
}
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter($layout);
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditDangerousController
|
||||
extends DiffusionRepositoryEditController {
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
|
@ -13,11 +13,31 @@ final class DiffusionRepositoryEditDangerousController
|
|||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
if (!$repository->canAllowDangerousChanges()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
$panel_uri = id(new DiffusionRepositoryBasicsManagementPanel())
|
||||
->setRepository($repository)
|
||||
->getPanelURI();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
if (!$repository->canAllowDangerousChanges()) {
|
||||
if ($repository->isSVN()) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Not in Danger'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'It is not possible for users to push any dangerous changes '.
|
||||
'to a Subversion repository. Pushes to a Subversion repository '.
|
||||
'can always be reverted and never destroy data.'))
|
||||
->addCancelButton($panel_uri);
|
||||
} else {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Unprotectable Repository'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'This repository can not be protected from dangerous changes '.
|
||||
'because Phabricator does not control what users are allowed '.
|
||||
'to push to it.'))
|
||||
->addCancelButton($panel_uri);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$xaction = id(new PhabricatorRepositoryTransaction())
|
||||
|
@ -30,33 +50,33 @@ final class DiffusionRepositoryEditDangerousController
|
|||
->setActor($viewer)
|
||||
->applyTransactions($repository, array($xaction));
|
||||
|
||||
return id(new AphrontReloadResponse())->setURI($edit_uri);
|
||||
return id(new AphrontReloadResponse())->setURI($panel_uri);
|
||||
}
|
||||
|
||||
$force = phutil_tag('tt', array(), '--force');
|
||||
|
||||
if ($repository->shouldAllowDangerousChanges()) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Prevent Dangerous changes?'))
|
||||
->appendChild(
|
||||
pht(
|
||||
'It will no longer be possible to delete branches from this '.
|
||||
'repository, or %s push to this repository.',
|
||||
$force))
|
||||
->addSubmitButton(pht('Prevent Dangerous Changes'))
|
||||
->addCancelButton($edit_uri);
|
||||
$title = pht('Prevent Dangerous Changes');
|
||||
$body = pht(
|
||||
'It will no longer be possible to delete branches from this '.
|
||||
'repository, or %s push to this repository.',
|
||||
$force);
|
||||
$submit = pht('Prevent Dangerous Changes');
|
||||
} else {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Allow Dangerous Changes?'))
|
||||
->appendChild(
|
||||
pht(
|
||||
'If you allow dangerous changes, it will be possible to delete '.
|
||||
'branches and %s push this repository. These operations can '.
|
||||
'alter a repository in a way that is difficult to recover from.',
|
||||
$force))
|
||||
->addSubmitButton(pht('Allow Dangerous Changes'))
|
||||
->addCancelButton($edit_uri);
|
||||
$title = pht('Allow Dangerous Changes');
|
||||
$body = pht(
|
||||
'If you allow dangerous changes, it will be possible to delete '.
|
||||
'branches and %s push this repository. These operations can '.
|
||||
'alter a repository in a way that is difficult to recover from.',
|
||||
$force);
|
||||
$submit = pht('Allow Dangerous Changes');
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle($title)
|
||||
->appendParagraph($body)
|
||||
->addSubmitButton($submit)
|
||||
->addCancelButton($panel_uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditDeleteController
|
||||
extends DiffusionRepositoryEditController {
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
|
@ -13,7 +13,9 @@ final class DiffusionRepositoryEditDeleteController
|
|||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$panel_uri = id(new DiffusionRepositoryBasicsManagementPanel())
|
||||
->setRepository($repository)
|
||||
->getPanelURI();
|
||||
|
||||
$dialog = new AphrontDialogView();
|
||||
$text_1 = pht(
|
||||
|
@ -40,7 +42,7 @@ final class DiffusionRepositoryEditDeleteController
|
|||
return $this->newDialog()
|
||||
->setTitle(pht('Really want to delete the repository?'))
|
||||
->appendChild($body)
|
||||
->addCancelButton($edit_uri, pht('Okay'));
|
||||
->addCancelButton($panel_uri, pht('Okay'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditEncodingController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$user = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_encoding = $repository->getDetail('encoding');
|
||||
$e_encoding = null;
|
||||
$errors = array();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_encoding = $request->getStr('encoding');
|
||||
|
||||
if (!$errors) {
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_encoding = PhabricatorRepositoryTransaction::TYPE_ENCODING;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_encoding)
|
||||
->setNewValue($v_encoding);
|
||||
|
||||
try {
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($user)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = $ex->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Encoding'));
|
||||
|
||||
$title = pht('Edit %s', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendRemarkupInstructions($this->getEncodingInstructions())
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('encoding')
|
||||
->setLabel(pht('Text Encoding'))
|
||||
->setValue($v_encoding)
|
||||
->setError($e_encoding))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Encoding'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Encoding'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form)
|
||||
->setFormErrors($errors);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function getEncodingInstructions() {
|
||||
return pht(<<<EOT
|
||||
If source code in this repository uses a character encoding other than UTF-8
|
||||
(for example, `ISO-8859-1`), specify it here.
|
||||
|
||||
**Normally, you can leave this field blank.** If your source code is written in
|
||||
ASCII or UTF-8, everything will work correctly.
|
||||
|
||||
Source files will be translated from the specified encoding to UTF-8 when they
|
||||
are read from the repository, before they are displayed in Diffusion.
|
||||
|
||||
See [[%s | UTF-8 and Character Encoding]] for more information on how
|
||||
Phabricator handles text encodings.
|
||||
EOT
|
||||
,
|
||||
PhabricatorEnv::getDoclink('User Guide: UTF-8 and Character Encoding'));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,288 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditHostingController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
private $serve;
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$this->serve = $request->getURIData('serve');
|
||||
|
||||
if (!$this->serve) {
|
||||
return $this->handleHosting($repository);
|
||||
} else {
|
||||
return $this->handleProtocols($repository);
|
||||
}
|
||||
}
|
||||
|
||||
public function handleHosting(PhabricatorRepository $repository) {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$v_hosting = $repository->isHosted();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$next_uri = $this->getRepositoryControllerURI($repository, 'edit/serve/');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_hosting = $request->getBool('hosting');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_hosting)
|
||||
->setNewValue($v_hosting);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($user)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Hosting'));
|
||||
|
||||
$title = pht('Edit Hosting (%s)', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$hosted_control = id(new AphrontFormRadioButtonControl())
|
||||
->setName('hosting')
|
||||
->setLabel(pht('Hosting'))
|
||||
->addButton(
|
||||
true,
|
||||
pht('Host Repository on Phabricator'),
|
||||
pht(
|
||||
'Phabricator will host this repository. Users will be able to '.
|
||||
'push commits to Phabricator. Phabricator will not pull '.
|
||||
'changes from elsewhere.'))
|
||||
->addButton(
|
||||
false,
|
||||
pht('Host Repository Elsewhere'),
|
||||
pht(
|
||||
'Phabricator will pull updates to this repository from a master '.
|
||||
'repository elsewhere (for example, on GitHub or Bitbucket). '.
|
||||
'Users will not be able to push commits to this repository.'))
|
||||
->setValue($v_hosting);
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink(
|
||||
'Diffusion User Guide: Repository Hosting');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
'Phabricator can host repositories, or it can track repositories '.
|
||||
'hosted elsewhere (like on GitHub or Bitbucket). For information '.
|
||||
'on configuring hosting, see [[ %s | Diffusion User Guide: '.
|
||||
'Repository Hosting]]',
|
||||
$doc_href))
|
||||
->appendChild($hosted_control)
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save and Continue'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Hosting'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
public function handleProtocols(PhabricatorRepository $repository) {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$type = $repository->getVersionControlSystem();
|
||||
$is_svn = ($type == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN);
|
||||
|
||||
$v_http_mode = $repository->getDetail(
|
||||
'serve-over-http',
|
||||
PhabricatorRepository::SERVE_OFF);
|
||||
$v_ssh_mode = $repository->getDetail(
|
||||
'serve-over-ssh',
|
||||
PhabricatorRepository::SERVE_OFF);
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$prev_uri = $this->getRepositoryControllerURI($repository, 'edit/hosting/');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_http_mode = $request->getStr('http');
|
||||
$v_ssh_mode = $request->getStr('ssh');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
|
||||
$type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
|
||||
|
||||
if (!$is_svn) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_http)
|
||||
->setNewValue($v_http_mode);
|
||||
}
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_ssh)
|
||||
->setNewValue($v_ssh_mode);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($user)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Protocols'));
|
||||
|
||||
$title = pht('Edit Protocols (%s)', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$rw_message = pht(
|
||||
'Phabricator will serve a read-write copy of this repository.');
|
||||
|
||||
if (!$repository->isHosted()) {
|
||||
$rw_message = array(
|
||||
$rw_message,
|
||||
phutil_tag('br'),
|
||||
phutil_tag('br'),
|
||||
pht(
|
||||
'%s: This repository is hosted elsewhere, so Phabricator can not '.
|
||||
'perform writes. This mode will act like "Read Only" for '.
|
||||
'repositories hosted elsewhere.',
|
||||
phutil_tag('strong', array(), pht('WARNING'))),
|
||||
);
|
||||
}
|
||||
|
||||
$ssh_control =
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('ssh')
|
||||
->setLabel(pht('SSH'))
|
||||
->setValue($v_ssh_mode)
|
||||
->addButton(
|
||||
PhabricatorRepository::SERVE_OFF,
|
||||
PhabricatorRepository::getProtocolAvailabilityName(
|
||||
PhabricatorRepository::SERVE_OFF),
|
||||
pht('Phabricator will not serve this repository over SSH.'))
|
||||
->addButton(
|
||||
PhabricatorRepository::SERVE_READONLY,
|
||||
PhabricatorRepository::getProtocolAvailabilityName(
|
||||
PhabricatorRepository::SERVE_READONLY),
|
||||
pht(
|
||||
'Phabricator will serve a read-only copy of this repository '.
|
||||
'over SSH.'))
|
||||
->addButton(
|
||||
PhabricatorRepository::SERVE_READWRITE,
|
||||
PhabricatorRepository::getProtocolAvailabilityName(
|
||||
PhabricatorRepository::SERVE_READWRITE),
|
||||
$rw_message);
|
||||
|
||||
$http_control =
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('http')
|
||||
->setLabel(pht('HTTP'))
|
||||
->setValue($v_http_mode)
|
||||
->addButton(
|
||||
PhabricatorRepository::SERVE_OFF,
|
||||
PhabricatorRepository::getProtocolAvailabilityName(
|
||||
PhabricatorRepository::SERVE_OFF),
|
||||
pht('Phabricator will not serve this repository over HTTP.'))
|
||||
->addButton(
|
||||
PhabricatorRepository::SERVE_READONLY,
|
||||
PhabricatorRepository::getProtocolAvailabilityName(
|
||||
PhabricatorRepository::SERVE_READONLY),
|
||||
pht(
|
||||
'Phabricator will serve a read-only copy of this repository '.
|
||||
'over HTTP.'))
|
||||
->addButton(
|
||||
PhabricatorRepository::SERVE_READWRITE,
|
||||
PhabricatorRepository::getProtocolAvailabilityName(
|
||||
PhabricatorRepository::SERVE_READWRITE),
|
||||
$rw_message);
|
||||
|
||||
if ($is_svn) {
|
||||
$http_control = id(new AphrontFormMarkupControl())
|
||||
->setLabel(pht('HTTP'))
|
||||
->setValue(
|
||||
phutil_tag(
|
||||
'em',
|
||||
array(),
|
||||
pht(
|
||||
'Phabricator does not currently support HTTP access to '.
|
||||
'Subversion repositories.')));
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
'Phabricator can serve repositories over various protocols. You can '.
|
||||
'configure server protocols here.'))
|
||||
->appendChild($ssh_control);
|
||||
|
||||
if (!PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')) {
|
||||
$form->appendRemarkupInstructions(
|
||||
pht(
|
||||
'NOTE: The configuration setting [[ %s | %s ]] is currently '.
|
||||
'disabled. You must enable it to activate authenticated access '.
|
||||
'to repositories over HTTP.',
|
||||
'/config/edit/diffusion.allow-http-auth/',
|
||||
'diffusion.allow-http-auth'));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild($http_control)
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Changes'))
|
||||
->addCancelButton($prev_uri, pht('Back')));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Protocols'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,91 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditStagingController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
|
||||
if (!$repository->supportsStaging()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_area = $repository->getHumanReadableDetail('staging-uri');
|
||||
if ($request->isFormPost()) {
|
||||
$v_area = $request->getStr('area');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_encoding = PhabricatorRepositoryTransaction::TYPE_STAGING_URI;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_encoding)
|
||||
->setNewValue($v_area);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Staging'));
|
||||
|
||||
$title = pht('Edit Staging (%s)', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
"To make it easier to run integration tests and builds on code ".
|
||||
"under review, you can configure a **Staging Area**. When `arc` ".
|
||||
"creates a diff, it will push a copy of the changes to the ".
|
||||
"configured staging area with a corresponding tag.".
|
||||
"\n\n".
|
||||
"IMPORTANT: This feature is new, experimental, and not supported. ".
|
||||
"Use it at your own risk."))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Staging Area URI'))
|
||||
->setName('area')
|
||||
->setValue($v_area))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Staging'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditStorageController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_local = $repository->getHumanReadableDetail('local-path');
|
||||
$errors = array();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Storage'));
|
||||
|
||||
$title = pht('Edit %s', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$service_phid = $repository->getAlmanacServicePHID();
|
||||
if ($service_phid) {
|
||||
$handles = $this->loadViewerHandles(array($service_phid));
|
||||
$v_service = $handles[$service_phid]->renderLink();
|
||||
} else {
|
||||
$v_service = phutil_tag(
|
||||
'em',
|
||||
array(),
|
||||
pht('Local'));
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setLabel(pht('Storage Service'))
|
||||
->setValue($v_service))
|
||||
->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setName('local')
|
||||
->setLabel(pht('Storage Path'))
|
||||
->setValue($v_local))
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
"You can not adjust the local path for this repository from the ".
|
||||
"web interface. To edit it, run this command:\n\n %s",
|
||||
sprintf(
|
||||
'phabricator/ $ ./bin/repository edit %s --as %s --local-path ...',
|
||||
$repository->getMonogram(),
|
||||
$viewer->getUsername())))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton($edit_uri, pht('Done')));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Storage'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditSubversionController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
throw new Exception(
|
||||
pht('Git and Mercurial do not support editing SVN properties!'));
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
break;
|
||||
default:
|
||||
throw new Exception(
|
||||
pht('Repository has unknown version control system!'));
|
||||
}
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_subpath = $repository->getHumanReadableDetail('svn-subpath');
|
||||
$v_uuid = $repository->getUUID();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_subpath = $request->getStr('subpath');
|
||||
$v_uuid = $request->getStr('uuid');
|
||||
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_subpath = PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH;
|
||||
$type_uuid = PhabricatorRepositoryTransaction::TYPE_UUID;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_subpath)
|
||||
->setNewValue($v_subpath);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_uuid)
|
||||
->setNewValue($v_uuid);
|
||||
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
}
|
||||
|
||||
$content = array();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Subversion Info'));
|
||||
|
||||
$title = pht('Edit Subversion Info (%s)', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($viewer)
|
||||
->setObject($repository)
|
||||
->execute();
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions(
|
||||
pht(
|
||||
"You can set the **Repository UUID**, which will help Phabriactor ".
|
||||
"provide better context in some cases. You can find the UUID of a ".
|
||||
"repository by running `%s`.\n\n".
|
||||
"If you want to import only part of a repository, like `trunk/`, ".
|
||||
"you can set a path in **Import Only**. Phabricator will ignore ".
|
||||
"commits which do not affect this path.",
|
||||
'svn info'))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('uuid')
|
||||
->setLabel(pht('Repository UUID'))
|
||||
->setValue($v_uuid))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('subpath')
|
||||
->setLabel(pht('Import Only'))
|
||||
->setValue($v_subpath))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Subversion Info'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Subversion'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditUpdateController
|
||||
extends DiffusionRepositoryEditController {
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
|
@ -13,7 +13,9 @@ final class DiffusionRepositoryEditUpdateController
|
|||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$panel_uri = id(new DiffusionRepositoryStatusManagementPanel())
|
||||
->setRepository($repository)
|
||||
->getPanelURI();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$params = array(
|
||||
|
@ -26,7 +28,7 @@ final class DiffusionRepositoryEditUpdateController
|
|||
->setUser($viewer)
|
||||
->execute();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
return id(new AphrontRedirectResponse())->setURI($panel_uri);
|
||||
}
|
||||
|
||||
$doc_name = 'Diffusion User Guide: Repository Updates';
|
||||
|
@ -58,7 +60,7 @@ final class DiffusionRepositoryEditUpdateController
|
|||
'To learn more about how Phabricator updates repositories, '.
|
||||
'read %s in the documentation.',
|
||||
$doc_link))
|
||||
->addCancelButton($edit_uri)
|
||||
->addCancelButton($panel_uri)
|
||||
->addSubmitButton(pht('Schedule Update'));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryEditproController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$engine = id(new DiffusionRepositoryEditEngine())
|
||||
->setController($this);
|
||||
|
||||
$id = $request->getURIData('id');
|
||||
if (!$id) {
|
||||
$this->requireApplicationCapability(
|
||||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
|
||||
$vcs = $request->getStr('vcs');
|
||||
$vcs_types = PhabricatorRepositoryType::getRepositoryTypeMap();
|
||||
if (empty($vcs_types[$vcs])) {
|
||||
return $this->buildVCSTypeResponse();
|
||||
}
|
||||
|
||||
$engine
|
||||
->addContextParameter('vcs', $vcs)
|
||||
->setVersionControlSystem($vcs);
|
||||
}
|
||||
|
||||
return $engine->buildResponse();
|
||||
}
|
||||
|
||||
private function buildVCSTypeResponse() {
|
||||
$vcs_types = PhabricatorRepositoryType::getRepositoryTypeMap();
|
||||
|
||||
$request = $this->getRequest();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Create Repository'));
|
||||
$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);
|
||||
|
||||
$create_uri = $request->getRequestURI();
|
||||
|
||||
foreach ($vcs_types as $vcs_key => $vcs_type) {
|
||||
$action = id(new PHUIActionPanelView())
|
||||
->setIcon(idx($vcs_type, 'icon'))
|
||||
->setHeader(idx($vcs_type, 'create.header'))
|
||||
->setHref($create_uri->alter('vcs', $vcs_key))
|
||||
->setSubheader(idx($vcs_type, 'create.subheader'));
|
||||
|
||||
$layout->addColumn($action);
|
||||
}
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter($layout);
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,16 +15,9 @@ final class DiffusionRepositoryListController extends DiffusionController {
|
|||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$can_create = $this->hasApplicationCapability(
|
||||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
|
||||
$crumbs->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('New Repository'))
|
||||
->setHref($this->getApplicationURI('new/'))
|
||||
->setDisabled(!$can_create)
|
||||
->setWorkflow(!$can_create)
|
||||
->setIcon('fa-plus-square'));
|
||||
id(new DiffusionRepositoryEditEngine())
|
||||
->setViewer($this->getViewer())
|
||||
->addActionToCrumbs($crumbs);
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
|
|
@ -1,129 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryManageController
|
||||
abstract class DiffusionRepositoryManageController
|
||||
extends DiffusionController {
|
||||
|
||||
private $navigation;
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
// TODO: This is messy for now; the mobile menu should be set automatically
|
||||
// when the body content is a two-column view with navigation.
|
||||
if ($this->navigation) {
|
||||
return $this->navigation->getMenu();
|
||||
if ($this->hasDiffusionRequest()) {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$crumbs->addTextCrumb(
|
||||
$repository->getDisplayName(),
|
||||
$repository->getURI());
|
||||
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Manage'),
|
||||
$repository->getPathURI('manage/'));
|
||||
}
|
||||
return parent::buildApplicationMenu();
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContext();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$panels = DiffusionRepositoryManagementPanel::getAllPanels();
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$panel
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->setController($this);
|
||||
}
|
||||
|
||||
$selected = $request->getURIData('panel');
|
||||
if (!strlen($selected)) {
|
||||
$selected = head_key($panels);
|
||||
}
|
||||
|
||||
if (empty($panels[$selected])) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$nav = $this->renderSideNav($repository, $panels, $selected);
|
||||
$this->navigation = $nav;
|
||||
|
||||
$panel = $panels[$selected];
|
||||
|
||||
$content = $panel->buildManagementPanelContent();
|
||||
|
||||
$title = array(
|
||||
$panel->getManagementPanelLabel(),
|
||||
$repository->getDisplayName(),
|
||||
);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$repository->getDisplayName(),
|
||||
$repository->getURI());
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Manage'),
|
||||
$repository->getPathURI('manage/'));
|
||||
$crumbs->addTextCrumb($panel->getManagementPanelLabel());
|
||||
|
||||
$header_text = pht(
|
||||
'%s: %s',
|
||||
$repository->getDisplayName(),
|
||||
$panel->getManagementPanelLabel());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($header_text)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
if ($repository->isTracked()) {
|
||||
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
|
||||
} else {
|
||||
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
|
||||
}
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setNavigation($nav)
|
||||
->setMainColumn($content);
|
||||
|
||||
$curtain = $panel->buildManagementPanelCurtain();
|
||||
if ($curtain) {
|
||||
$view->setCurtain($curtain);
|
||||
}
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function renderSideNav(
|
||||
PhabricatorRepository $repository,
|
||||
array $panels,
|
||||
$selected) {
|
||||
|
||||
$base_uri = $repository->getPathURI('manage/');
|
||||
$base_uri = new PhutilURI($base_uri);
|
||||
|
||||
$nav = id(new AphrontSideNavFilterView())
|
||||
->setBaseURI($base_uri);
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$nav->addFilter(
|
||||
$panel->getManagementPanelKey(),
|
||||
$panel->getManagementPanelLabel());
|
||||
}
|
||||
|
||||
$nav->selectFilter($selected);
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
public function newTimeline(PhabricatorRepository $repository) {
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$repository,
|
||||
new PhabricatorRepositoryTransactionQuery());
|
||||
$timeline->setShouldTerminate(true);
|
||||
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryManagePanelsController
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
private $navigation;
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
// TODO: This is messy for now; the mobile menu should be set automatically
|
||||
// when the body content is a two-column view with navigation.
|
||||
if ($this->navigation) {
|
||||
return $this->navigation->getMenu();
|
||||
}
|
||||
return parent::buildApplicationMenu();
|
||||
}
|
||||
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContext();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$panels = DiffusionRepositoryManagementPanel::getAllPanels();
|
||||
|
||||
foreach ($panels as $key => $panel) {
|
||||
$panel
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->setController($this);
|
||||
|
||||
if (!$panel->shouldEnableForRepository($repository)) {
|
||||
unset($panels[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$selected = $request->getURIData('panel');
|
||||
if (!strlen($selected)) {
|
||||
$selected = head_key($panels);
|
||||
}
|
||||
|
||||
if (empty($panels[$selected])) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$nav = $this->renderSideNav($repository, $panels, $selected);
|
||||
$this->navigation = $nav;
|
||||
|
||||
$panel = $panels[$selected];
|
||||
|
||||
$content = $panel->buildManagementPanelContent();
|
||||
|
||||
$title = array(
|
||||
$panel->getManagementPanelLabel(),
|
||||
$repository->getDisplayName(),
|
||||
);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($panel->getManagementPanelLabel());
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$header_text = pht(
|
||||
'%s: %s',
|
||||
$repository->getDisplayName(),
|
||||
$panel->getManagementPanelLabel());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($header_text)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
if ($repository->isTracked()) {
|
||||
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
|
||||
} else {
|
||||
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
|
||||
}
|
||||
|
||||
$header->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('View Repository'))
|
||||
->setHref($repository->getURI())
|
||||
->setIcon('fa-code'));
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setNavigation($nav)
|
||||
->setMainColumn($content);
|
||||
|
||||
$curtain = $panel->buildManagementPanelCurtain();
|
||||
if ($curtain) {
|
||||
$view->setCurtain($curtain);
|
||||
}
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function renderSideNav(
|
||||
PhabricatorRepository $repository,
|
||||
array $panels,
|
||||
$selected) {
|
||||
|
||||
$base_uri = $repository->getPathURI('manage/');
|
||||
$base_uri = new PhutilURI($base_uri);
|
||||
|
||||
$nav = id(new AphrontSideNavFilterView())
|
||||
->setBaseURI($base_uri);
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$key = $panel->getManagementPanelKey();
|
||||
$label = $panel->getManagementPanelLabel();
|
||||
$icon = $panel->getManagementPanelIcon();
|
||||
$href = $panel->getPanelNavigationURI();
|
||||
|
||||
$item = id(new PHUIListItemView())
|
||||
->setKey($key)
|
||||
->setName($label)
|
||||
->setType(PHUIListItemView::TYPE_LINK)
|
||||
->setHref($href)
|
||||
->setIcon($icon);
|
||||
|
||||
$nav->addMenuItem($item);
|
||||
}
|
||||
|
||||
$nav->selectFilter($selected);
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
public function newTimeline(PhabricatorRepository $repository) {
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$repository,
|
||||
new PhabricatorRepositoryTransactionQuery());
|
||||
$timeline->setShouldTerminate(true);
|
||||
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryNewController extends DiffusionController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$this->requireApplicationCapability(
|
||||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
if ($request->getStr('type')) {
|
||||
switch ($request->getStr('type')) {
|
||||
case 'create':
|
||||
$uri = $this->getApplicationURI('create/');
|
||||
break;
|
||||
case 'import':
|
||||
default:
|
||||
$uri = $this->getApplicationURI('import/');
|
||||
break;
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($uri);
|
||||
}
|
||||
}
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink(
|
||||
'Diffusion User Guide: Repository Hosting');
|
||||
|
||||
$doc_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $doc_href,
|
||||
'target' => '_blank',
|
||||
),
|
||||
pht('Diffusion User Guide: Repository Hosting'));
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('type')
|
||||
->addButton(
|
||||
'create',
|
||||
pht('Create a New Hosted Repository'),
|
||||
array(
|
||||
pht(
|
||||
'Create a new, empty repository which Phabricator will host. '.
|
||||
'For instructions on configuring repository hosting, see %s.',
|
||||
$doc_link),
|
||||
))
|
||||
->addButton(
|
||||
'import',
|
||||
pht('Import an Existing External Repository'),
|
||||
pht(
|
||||
"Import a repository hosted somewhere else, like GitHub, ".
|
||||
"Bitbucket, or your organization's existing servers. ".
|
||||
"Phabricator will read changes from the repository but will ".
|
||||
"not host or manage it. The authoritative master version of ".
|
||||
"the repository will stay where it is now.")))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Continue'))
|
||||
->addCancelButton($this->getApplicationURI()));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('New Repository'));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Create or Import Repository'))
|
||||
->setForm($form);
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle(pht('New Repository'))
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($form_box);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositorySymbolsController
|
||||
extends DiffusionRepositoryEditController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
|
||||
$v_sources = $repository->getSymbolSources();
|
||||
$v_languages = $repository->getSymbolLanguages();
|
||||
if ($v_languages) {
|
||||
$v_languages = implode(', ', $v_languages);
|
||||
}
|
||||
$errors = array();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_sources = $request->getArr('sources');
|
||||
$v_languages = $request->getStrList('languages');
|
||||
$v_languages = array_map('phutil_utf8_strtolower', $v_languages);
|
||||
|
||||
if (!$errors) {
|
||||
$xactions = array();
|
||||
$template = id(new PhabricatorRepositoryTransaction());
|
||||
|
||||
$type_sources = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
|
||||
$type_lang = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_sources)
|
||||
->setNewValue($v_sources);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_lang)
|
||||
->setNewValue($v_languages);
|
||||
|
||||
try {
|
||||
id(new PhabricatorRepositoryEditor())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->applyTransactions($repository, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = $ex->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Edit Symbols'));
|
||||
|
||||
$title = pht('Edit Symbols (%s)', $repository->getName());
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setHeaderIcon('fa-pencil');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions($this->getInstructions())
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('languages')
|
||||
->setLabel(pht('Indexed Languages'))
|
||||
->setCaption(pht(
|
||||
'File extensions, separate with commas, for example: php, py. '.
|
||||
'Leave blank for "any".'))
|
||||
->setValue($v_languages))
|
||||
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setName('sources')
|
||||
->setLabel(pht('Uses Symbols From'))
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setValue($v_sources))
|
||||
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save'))
|
||||
->addCancelButton($edit_uri));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Symbols'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setForm($form)
|
||||
->setFormErrors($errors);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$form_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function getInstructions() {
|
||||
return pht(<<<EOT
|
||||
Configure Symbols for this repository.
|
||||
|
||||
See [[%s | Symbol Indexes]] for more information on using symbols.
|
||||
EOT
|
||||
,
|
||||
PhabricatorEnv::getDoclink(
|
||||
'Diffusion User Guide: Symbol Indexes'));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryTestAutomationController
|
||||
extends DiffusionRepositoryEditController {
|
||||
extends DiffusionRepositoryManageController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
|
@ -13,7 +13,9 @@ final class DiffusionRepositoryTestAutomationController
|
|||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
|
||||
$panel_uri = id(new DiffusionRepositoryAutomationManagementPanel())
|
||||
->setRepository($repository)
|
||||
->getPanelURI();
|
||||
|
||||
if (!$repository->canPerformAutomation()) {
|
||||
return $this->newDialog()
|
||||
|
@ -23,7 +25,7 @@ final class DiffusionRepositoryTestAutomationController
|
|||
'You can not run a configuration test for this repository '.
|
||||
'because you have not configured repository automation yet. '.
|
||||
'Configure it first, then test the configuration.'))
|
||||
->addCancelButton($edit_uri);
|
||||
->addCancelButton($panel_uri);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
|
@ -63,7 +65,7 @@ final class DiffusionRepositoryTestAutomationController
|
|||
'If you run into write failures despite passing this test, '.
|
||||
'it suggests that your setup is nearly correct but authentication '.
|
||||
'is probably not fully configured.'))
|
||||
->addCancelButton($edit_uri)
|
||||
->addCancelButton($panel_uri)
|
||||
->addSubmitButton(pht('Start Test'));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryURICredentialController
|
||||
extends DiffusionController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContextForEdit();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$id = $request->getURIData('id');
|
||||
$uri = id(new PhabricatorRepositoryURIQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->withRepositories(array($repository))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$uri) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$is_builtin = $uri->isBuiltin();
|
||||
$has_credential = (bool)$uri->getCredentialPHID();
|
||||
$view_uri = $uri->getViewURI();
|
||||
$is_remove = ($request->getURIData('action') == 'remove');
|
||||
|
||||
if ($is_builtin) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Builtin URIs Do Not Use Credentials'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You can not set a credential for builtin URIs which Phabricator '.
|
||||
'hosts and serves. Phabricator does not fetch from these URIs or '.
|
||||
'push to these URIs, and does not need credentials to '.
|
||||
'authenticate any activity against them.'))
|
||||
->addCancelButton($view_uri);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$xactions = array();
|
||||
|
||||
if ($is_remove) {
|
||||
$new_phid = null;
|
||||
} else {
|
||||
$new_phid = $request->getStr('credentialPHID');
|
||||
}
|
||||
|
||||
$type_credential = PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL;
|
||||
|
||||
$xactions[] = id(new PhabricatorRepositoryURITransaction())
|
||||
->setTransactionType($type_credential)
|
||||
->setNewValue($new_phid);
|
||||
|
||||
$editor = id(new DiffusionURIEditor())
|
||||
->setActor($viewer)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->applyTransactions($uri, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
}
|
||||
|
||||
$command_engine = $uri->newCommandEngine();
|
||||
$is_supported = $command_engine->isCredentialSupported();
|
||||
|
||||
$body = null;
|
||||
$form = null;
|
||||
$width = AphrontDialogView::WIDTH_DEFAULT;
|
||||
if ($is_remove) {
|
||||
if ($has_credential) {
|
||||
$title = pht('Remove Credential');
|
||||
$body = pht(
|
||||
'This credential will no longer be used to authenticate activity '.
|
||||
'against this URI.');
|
||||
$button = pht('Remove Credential');
|
||||
} else {
|
||||
$title = pht('No Credential');
|
||||
$body = pht(
|
||||
'This URI does not have an associated credential.');
|
||||
$button = null;
|
||||
}
|
||||
} else if (!$is_supported) {
|
||||
$title = pht('Unauthenticated Protocol');
|
||||
$body = pht(
|
||||
'The protocol for this URI ("%s") does not use authentication, so '.
|
||||
'you can not provide a credential.',
|
||||
$command_engine->getDisplayProtocol());
|
||||
$button = null;
|
||||
} else {
|
||||
$effective_uri = $uri->getEffectiveURI();
|
||||
|
||||
$label = $command_engine->getPassphraseCredentialLabel();
|
||||
$credential_type = $command_engine->getPassphraseDefaultCredentialType();
|
||||
|
||||
$provides_type = $command_engine->getPassphraseProvidesCredentialType();
|
||||
$options = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withIsDestroyed(false)
|
||||
->withProvidesTypes(array($provides_type))
|
||||
->execute();
|
||||
|
||||
$control = id(new PassphraseCredentialControl())
|
||||
->setName('credentialPHID')
|
||||
->setLabel($label)
|
||||
->setValue($uri->getCredentialPHID())
|
||||
->setCredentialType($credential_type)
|
||||
->setOptions($options);
|
||||
|
||||
$default_user = $effective_uri->getUser();
|
||||
if (strlen($default_user)) {
|
||||
$control->setDefaultUsername($default_user);
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setViewer($viewer)
|
||||
->appendControl($control);
|
||||
|
||||
if ($has_credential) {
|
||||
$title = pht('Update Credential');
|
||||
$button = pht('Update Credential');
|
||||
} else {
|
||||
$title = pht('Set Credential');
|
||||
$button = pht('Set Credential');
|
||||
}
|
||||
|
||||
$width = AphrontDialogView::WIDTH_FORM;
|
||||
}
|
||||
|
||||
$dialog = $this->newDialog()
|
||||
->setWidth($width)
|
||||
->setTitle($title)
|
||||
->addCancelButton($view_uri);
|
||||
|
||||
if ($body) {
|
||||
$dialog->appendParagraph($body);
|
||||
}
|
||||
|
||||
if ($form) {
|
||||
$dialog->appendForm($form);
|
||||
}
|
||||
|
||||
if ($button) {
|
||||
$dialog->addSubmitButton($button);
|
||||
}
|
||||
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,16 @@ final class DiffusionRepositoryURIDisableController
|
|||
$is_disabled = $uri->getIsDisabled();
|
||||
$view_uri = $uri->getViewURI();
|
||||
|
||||
if ($uri->isBuiltin()) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Builtin URI'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You can not manually disable builtin URIs. To hide a builtin '.
|
||||
'URI, configure its "Display" behavior instead.'))
|
||||
->addCancelButton($view_uri);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$xactions = array();
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ final class DiffusionRepositoryURIViewController
|
|||
|
||||
private function buildCurtain(PhabricatorRepositoryURI $uri) {
|
||||
$viewer = $this->getViewer();
|
||||
$repository = $uri->getRepository();
|
||||
$id = $uri->getID();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
|
@ -89,7 +90,6 @@ final class DiffusionRepositoryURIViewController
|
|||
$uri,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
|
||||
$curtain = $this->newCurtainView($uri);
|
||||
|
||||
$edit_uri = $uri->getEditURI();
|
||||
|
@ -102,6 +102,43 @@ final class DiffusionRepositoryURIViewController
|
|||
->setWorkflow(!$can_edit)
|
||||
->setDisabled(!$can_edit));
|
||||
|
||||
$credential_uri = $repository->getPathURI("uri/credential/{$id}/edit/");
|
||||
$remove_uri = $repository->getPathURI("uri/credential/{$id}/remove/");
|
||||
$has_credential = (bool)$uri->getCredentialPHID();
|
||||
|
||||
if ($uri->isBuiltin()) {
|
||||
$can_credential = false;
|
||||
} else if (!$uri->newCommandEngine()->isCredentialSupported()) {
|
||||
$can_credential = false;
|
||||
} else {
|
||||
$can_credential = true;
|
||||
}
|
||||
|
||||
$can_update = ($can_edit && $can_credential);
|
||||
$can_remove = ($can_edit && $has_credential);
|
||||
|
||||
if ($has_credential) {
|
||||
$credential_name = pht('Update Credential');
|
||||
} else {
|
||||
$credential_name = pht('Set Credential');
|
||||
}
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-key')
|
||||
->setName($credential_name)
|
||||
->setHref($credential_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit));
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-times')
|
||||
->setName(pht('Remove Credential'))
|
||||
->setHref($remove_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_remove));
|
||||
|
||||
if ($uri->getIsDisabled()) {
|
||||
$disable_name = pht('Enable URI');
|
||||
$disable_icon = 'fa-check';
|
||||
|
@ -110,7 +147,9 @@ final class DiffusionRepositoryURIViewController
|
|||
$disable_icon = 'fa-ban';
|
||||
}
|
||||
|
||||
$disable_uri = $uri->getRepository()->getPathURI("uri/disable/{$id}/");
|
||||
$can_disable = ($can_edit && !$uri->isBuiltin());
|
||||
|
||||
$disable_uri = $repository->getPathURI("uri/disable/{$id}/");
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
|
@ -118,7 +157,7 @@ final class DiffusionRepositoryURIViewController
|
|||
->setName($disable_name)
|
||||
->setHref($disable_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit));
|
||||
->setDisabled(!$can_disable));
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
@ -130,7 +169,84 @@ final class DiffusionRepositoryURIViewController
|
|||
->setUser($viewer);
|
||||
|
||||
$properties->addProperty(pht('URI'), $uri->getDisplayURI());
|
||||
$properties->addProperty(pht('Credential'), 'TODO');
|
||||
|
||||
$credential_phid = $uri->getCredentialPHID();
|
||||
$command_engine = $uri->newCommandEngine();
|
||||
$is_optional = $command_engine->isCredentialOptional();
|
||||
$is_supported = $command_engine->isCredentialSupported();
|
||||
$is_builtin = $uri->isBuiltin();
|
||||
|
||||
if ($is_builtin) {
|
||||
$credential_icon = 'fa-circle-o';
|
||||
$credential_color = 'grey';
|
||||
$credential_label = pht('Builtin');
|
||||
$credential_note = pht('Builtin URIs do not use credentials.');
|
||||
} else if (!$is_supported) {
|
||||
$credential_icon = 'fa-circle-o';
|
||||
$credential_color = 'grey';
|
||||
$credential_label = pht('Not Supported');
|
||||
$credential_note = pht('This protocol does not support authentication.');
|
||||
} else if (!$credential_phid) {
|
||||
if ($is_optional) {
|
||||
$credential_icon = 'fa-circle-o';
|
||||
$credential_color = 'green';
|
||||
$credential_label = pht('No Credential');
|
||||
$credential_note = pht('Configured for anonymous access.');
|
||||
} else {
|
||||
$credential_icon = 'fa-times';
|
||||
$credential_color = 'red';
|
||||
$credential_label = pht('Required');
|
||||
$credential_note = pht('Credential required but not configured.');
|
||||
}
|
||||
} else {
|
||||
// Don't raise a policy exception if we can't see the credential.
|
||||
$credentials = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($credential_phid))
|
||||
->execute();
|
||||
$credential = head($credentials);
|
||||
|
||||
if (!$credential) {
|
||||
$handles = $viewer->loadHandles(array($credential_phid));
|
||||
$handle = $handles[$credential_phid];
|
||||
if ($handle->getPolicyFiltered()) {
|
||||
$credential_icon = 'fa-lock';
|
||||
$credential_color = 'grey';
|
||||
$credential_label = pht('Restricted');
|
||||
$credential_note = pht(
|
||||
'You do not have permission to view the configured '.
|
||||
'credential.');
|
||||
} else {
|
||||
$credential_icon = 'fa-times';
|
||||
$credential_color = 'red';
|
||||
$credential_label = pht('Invalid');
|
||||
$credential_note = pht('Configured credential is invalid.');
|
||||
}
|
||||
} else {
|
||||
$provides = $credential->getProvidesType();
|
||||
$needs = $command_engine->getPassphraseProvidesCredentialType();
|
||||
if ($provides != $needs) {
|
||||
$credential_icon = 'fa-times';
|
||||
$credential_color = 'red';
|
||||
$credential_label = pht('Wrong Type');
|
||||
} else {
|
||||
$credential_icon = 'fa-check';
|
||||
$credential_color = 'green';
|
||||
$credential_label = $command_engine->getPassphraseCredentialLabel();
|
||||
}
|
||||
$credential_note = $viewer->renderHandle($credential_phid);
|
||||
}
|
||||
}
|
||||
|
||||
$credential_item = id(new PHUIStatusItemView())
|
||||
->setIcon($credential_icon, $credential_color)
|
||||
->setTarget(phutil_tag('strong', array(), $credential_label))
|
||||
->setNote($credential_note);
|
||||
|
||||
$credential_view = id(new PHUIStatusListView())
|
||||
->addItem($credential_item);
|
||||
|
||||
$properties->addProperty(pht('Credential'), $credential_view);
|
||||
|
||||
|
||||
$io_type = $uri->getEffectiveIOType();
|
||||
|
|
|
@ -219,6 +219,7 @@ final class DiffusionServeController extends DiffusionController {
|
|||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIdentifiers(array($identifier))
|
||||
->needURIs(true)
|
||||
->executeOne();
|
||||
if (!$repository) {
|
||||
return new PhabricatorVCSResponse(
|
||||
|
@ -266,22 +267,32 @@ final class DiffusionServeController extends DiffusionController {
|
|||
// token from SSH. If they're using HTTP username + password auth, they
|
||||
// have to obey the normal HTTP rules.
|
||||
} else {
|
||||
switch ($repository->getServeOverHTTP()) {
|
||||
case PhabricatorRepository::SERVE_READONLY:
|
||||
if ($is_push) {
|
||||
return new PhabricatorVCSResponse(
|
||||
403,
|
||||
pht('This repository is read-only over HTTP.'));
|
||||
}
|
||||
break;
|
||||
case PhabricatorRepository::SERVE_READWRITE:
|
||||
// We'll check for push capability below.
|
||||
break;
|
||||
case PhabricatorRepository::SERVE_OFF:
|
||||
default:
|
||||
// For now, we don't distinguish between HTTP and HTTPS-originated
|
||||
// requests that are proxied within the cluster, so the user can connect
|
||||
// with HTTPS but we may be on HTTP by the time we reach this part of
|
||||
// the code. Allow things to move forward as long as either protocol
|
||||
// can be served.
|
||||
$proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS;
|
||||
$proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP;
|
||||
|
||||
$can_read =
|
||||
$repository->canServeProtocol($proto_https, false) ||
|
||||
$repository->canServeProtocol($proto_http, false);
|
||||
if (!$can_read) {
|
||||
return new PhabricatorVCSResponse(
|
||||
403,
|
||||
pht('This repository is not available over HTTP.'));
|
||||
}
|
||||
|
||||
if ($is_push) {
|
||||
$can_write =
|
||||
$repository->canServeProtocol($proto_https, true) ||
|
||||
$repository->canServeProtocol($proto_http, true);
|
||||
if (!$can_write) {
|
||||
return new PhabricatorVCSResponse(
|
||||
403,
|
||||
pht('This repository is not available over HTTP.'));
|
||||
pht('This repository is read-only over HTTP.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Filter a list of repositories, removing repositories not local to the
|
||||
* current device.
|
||||
*/
|
||||
final class DiffusionLocalRepositoryFilter extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
private $device;
|
||||
private $repositories;
|
||||
private $rejectionReasons;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function setDevice(AlmanacDevice $device = null) {
|
||||
$this->device = $device;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDevice() {
|
||||
return $this->device;
|
||||
}
|
||||
|
||||
public function setRepositories(array $repositories) {
|
||||
$this->repositories = $repositories;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRepositories() {
|
||||
return $this->repositories;
|
||||
}
|
||||
|
||||
public function setRejectionReasons($rejection_reasons) {
|
||||
$this->rejectionReasons = $rejection_reasons;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRejectionReasons() {
|
||||
return $this->rejectionReasons;
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
$repositories = $this->getRepositories();
|
||||
$device = $this->getDevice();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$reasons = array();
|
||||
|
||||
$service_phids = array();
|
||||
foreach ($repositories as $key => $repository) {
|
||||
$service_phid = $repository->getAlmanacServicePHID();
|
||||
|
||||
// If the repository is bound to a service but this host is not a
|
||||
// recognized device, or vice versa, don't pull the repository unless
|
||||
// we're sure it's safe because the repository has no local working copy
|
||||
// or the working copy already exists on disk.
|
||||
$is_cluster_repo = (bool)$service_phid;
|
||||
$is_cluster_device = (bool)$device;
|
||||
if ($is_cluster_repo != $is_cluster_device) {
|
||||
$has_working_copy = $repository->hasLocalWorkingCopy();
|
||||
if ($is_cluster_device) {
|
||||
if (!$has_working_copy) {
|
||||
$reasons[$key] = pht(
|
||||
'Repository "%s" is not a cluster repository, but the current '.
|
||||
'host is a cluster device ("%s") and updating this repository '.
|
||||
'would create a new local working copy. This is dangerous, so '.
|
||||
'the repository will not be updated on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$device->getName());
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$reasons[$key] = pht(
|
||||
'Repository "%s" is a cluster repository, but the current host '.
|
||||
'is not a cluster device (it has no device ID), so the '.
|
||||
'repository will not be updated on this host.',
|
||||
$repository->getDisplayName());
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($service_phid) {
|
||||
$service_phids[] = $service_phid;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$device) {
|
||||
$this->rejectionReasons = $reasons;
|
||||
return $repositories;
|
||||
}
|
||||
|
||||
$device_phid = $device->getPHID();
|
||||
|
||||
if ($service_phids) {
|
||||
// We could include `withDevicePHIDs()` here to pull a smaller result
|
||||
// set, but we can provide more helpful diagnostic messages below if
|
||||
// we fetch a little more data.
|
||||
$services = id(new AlmanacServiceQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs($service_phids)
|
||||
->withServiceTypes(
|
||||
array(
|
||||
AlmanacClusterRepositoryServiceType::SERVICETYPE,
|
||||
))
|
||||
->needBindings(true)
|
||||
->execute();
|
||||
$services = mpull($services, null, 'getPHID');
|
||||
} else {
|
||||
$services = array();
|
||||
}
|
||||
|
||||
foreach ($repositories as $key => $repository) {
|
||||
$service_phid = $repository->getAlmanacServicePHID();
|
||||
|
||||
if (!$service_phid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$service = idx($services, $service_phid);
|
||||
if (!$service) {
|
||||
$reasons[$key] = pht(
|
||||
'Repository "%s" is on cluster service "%s", but that service '.
|
||||
'could not be loaded, so the repository will not be updated on '.
|
||||
'this host.',
|
||||
$repository->getDisplayName(),
|
||||
$service_phid);
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$bindings = $service->getBindings();
|
||||
$bindings = mgroup($bindings, 'getDevicePHID');
|
||||
$bindings = idx($bindings, $device_phid);
|
||||
if (!$bindings) {
|
||||
$reasons[$key] = pht(
|
||||
'Repository "%s" is on cluster service "%s", but that service is '.
|
||||
'not bound to this device ("%s"), so the repository will not be '.
|
||||
'updated on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$service->getName(),
|
||||
$device->getName());
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$all_disabled = true;
|
||||
foreach ($bindings as $binding) {
|
||||
if (!$binding->getIsDisabled()) {
|
||||
$all_disabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($all_disabled) {
|
||||
$reasons[$key] = pht(
|
||||
'Repository "%s" is on cluster service "%s", but the binding '.
|
||||
'between that service and this device ("%s") is disabled, so it '.
|
||||
'can not be updated on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$service->getName(),
|
||||
$device->getName());
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a valid service that is actively bound to the current host
|
||||
// device, so we're good to go.
|
||||
}
|
||||
|
||||
$this->rejectionReasons = $reasons;
|
||||
return $repositories;
|
||||
}
|
||||
|
||||
}
|
|
@ -40,11 +40,51 @@ final class DiffusionRepositoryEditEngine
|
|||
$viewer = $this->getViewer();
|
||||
$repository = PhabricatorRepository::initializeNewRepository($viewer);
|
||||
|
||||
$repository->setDetail('newly-initialized', true);
|
||||
|
||||
$vcs = $this->getVersionControlSystem();
|
||||
if ($vcs) {
|
||||
$repository->setVersionControlSystem($vcs);
|
||||
}
|
||||
|
||||
// Pick a random open service to allocate this repository on, if any exist.
|
||||
// If there are no services, we aren't in cluster mode and will allocate
|
||||
// locally. If there are services but none permit allocations, we fail.
|
||||
|
||||
// Eventually we can make this more flexible, but this rule is a reasonable
|
||||
// starting point as we begin to deploy cluster services.
|
||||
|
||||
$services = id(new AlmanacServiceQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withServiceTypes(
|
||||
array(
|
||||
AlmanacClusterRepositoryServiceType::SERVICETYPE,
|
||||
))
|
||||
->needProperties(true)
|
||||
->execute();
|
||||
if ($services) {
|
||||
// Filter out services which do not permit new allocations.
|
||||
foreach ($services as $key => $possible_service) {
|
||||
if ($possible_service->getAlmanacPropertyValue('closed')) {
|
||||
unset($services[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$services) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This install is configured in cluster mode, but all available '.
|
||||
'repository cluster services are closed to new allocations. '.
|
||||
'At least one service must be open to allow new allocations to '.
|
||||
'take place.'));
|
||||
}
|
||||
|
||||
shuffle($services);
|
||||
$service = head($services);
|
||||
|
||||
$repository->setAlmanacServicePHID($service->getPHID());
|
||||
}
|
||||
|
||||
return $repository;
|
||||
}
|
||||
|
||||
|
@ -85,6 +125,77 @@ final class DiffusionRepositoryEditEngine
|
|||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
}
|
||||
|
||||
protected function newPages($object) {
|
||||
$panels = DiffusionRepositoryManagementPanel::getAllPanels();
|
||||
|
||||
$pages = array();
|
||||
$uris = array();
|
||||
foreach ($panels as $panel_key => $panel) {
|
||||
$panel->setRepository($object);
|
||||
|
||||
$uris[$panel_key] = $panel->getPanelURI();
|
||||
|
||||
$page = $panel->newEditEnginePage();
|
||||
if (!$page) {
|
||||
continue;
|
||||
}
|
||||
$pages[] = $page;
|
||||
}
|
||||
|
||||
$basics_key = DiffusionRepositoryBasicsManagementPanel::PANELKEY;
|
||||
$basics_uri = $uris[$basics_key];
|
||||
|
||||
$more_pages = array(
|
||||
id(new PhabricatorEditPage())
|
||||
->setKey('encoding')
|
||||
->setLabel(pht('Text Encoding'))
|
||||
->setViewURI($basics_uri)
|
||||
->setFieldKeys(
|
||||
array(
|
||||
'encoding',
|
||||
)),
|
||||
id(new PhabricatorEditPage())
|
||||
->setKey('extensions')
|
||||
->setLabel(pht('Extensions'))
|
||||
->setIsDefault(true),
|
||||
);
|
||||
|
||||
foreach ($more_pages as $page) {
|
||||
$pages[] = $page;
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
protected function willConfigureFields($object, array $fields) {
|
||||
// Change the default field order so related fields are adjacent.
|
||||
$after = array(
|
||||
'policy.edit' => array('policy.push'),
|
||||
);
|
||||
|
||||
$result = array();
|
||||
foreach ($fields as $key => $value) {
|
||||
$result[$key] = $value;
|
||||
|
||||
if (!isset($after[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($after[$key] as $next_key) {
|
||||
if (!isset($fields[$next_key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($result[$next_key]);
|
||||
$result[$next_key] = $fields[$next_key];
|
||||
unset($fields[$next_key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
protected function buildCustomEditFields($object) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
@ -99,6 +210,27 @@ final class DiffusionRepositoryEditEngine
|
|||
$autoclose_value = $object->getDetail('close-commits-filter', array());
|
||||
$autoclose_value = array_keys($autoclose_value);
|
||||
|
||||
$automation_instructions = pht(
|
||||
"Configure **Repository Automation** to allow Phabricator to ".
|
||||
"write to this repository.".
|
||||
"\n\n".
|
||||
"IMPORTANT: This feature is new, experimental, and not supported. ".
|
||||
"Use it at your own risk.");
|
||||
|
||||
$staging_instructions = pht(
|
||||
"To make it easier to run integration tests and builds on code ".
|
||||
"under review, you can configure a **Staging Area**. When `arc` ".
|
||||
"creates a diff, it will push a copy of the changes to the ".
|
||||
"configured staging area with a corresponding tag.".
|
||||
"\n\n".
|
||||
"IMPORTANT: This feature is new, experimental, and not supported. ".
|
||||
"Use it at your own risk.");
|
||||
|
||||
$subpath_instructions = pht(
|
||||
'If you want to import only part of a repository, like `trunk/`, '.
|
||||
'you can set a path in **Import Only**. Phabricator will ignore '.
|
||||
'commits which do not affect this path.');
|
||||
|
||||
return array(
|
||||
id(new PhabricatorSelectEditField())
|
||||
->setKey('vcs')
|
||||
|
@ -211,6 +343,17 @@ final class DiffusionRepositoryEditEngine
|
|||
->setConduitDescription(pht('Set the autoclose branches.'))
|
||||
->setConduitTypeDescription(pht('New default tracked branchs.'))
|
||||
->setValue($autoclose_value),
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('importOnly')
|
||||
->setLabel(pht('Import Only'))
|
||||
->setTransactionType(
|
||||
PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH)
|
||||
->setIsCopyable(true)
|
||||
->setDescription(pht('Subpath to selectively import.'))
|
||||
->setConduitDescription(pht('Set the subpath to import.'))
|
||||
->setConduitTypeDescription(pht('New subpath to import.'))
|
||||
->setValue($object->getDetail('svn-subpath'))
|
||||
->setControlInstructions($subpath_instructions),
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('stagingAreaURI')
|
||||
->setLabel(pht('Staging Area URI'))
|
||||
|
@ -220,7 +363,8 @@ final class DiffusionRepositoryEditEngine
|
|||
->setDescription(pht('Staging area URI.'))
|
||||
->setConduitDescription(pht('Set the staging area URI.'))
|
||||
->setConduitTypeDescription(pht('New staging area URI.'))
|
||||
->setValue($object->getStagingURI()),
|
||||
->setValue($object->getStagingURI())
|
||||
->setControlInstructions($staging_instructions),
|
||||
id(new PhabricatorDatasourceEditField())
|
||||
->setKey('automationBlueprintPHIDs')
|
||||
->setLabel(pht('Use Blueprints'))
|
||||
|
@ -231,7 +375,8 @@ final class DiffusionRepositoryEditEngine
|
|||
->setDescription(pht('Automation blueprints.'))
|
||||
->setConduitDescription(pht('Change automation blueprints.'))
|
||||
->setConduitTypeDescription(pht('New blueprint PHIDs.'))
|
||||
->setValue($object->getAutomationBlueprintPHIDs()),
|
||||
->setValue($object->getAutomationBlueprintPHIDs())
|
||||
->setControlInstructions($automation_instructions),
|
||||
id(new PhabricatorStringListEditField())
|
||||
->setKey('symbolLanguages')
|
||||
->setLabel(pht('Languages'))
|
||||
|
|
|
@ -83,6 +83,67 @@ final class DiffusionURIEditEngine
|
|||
protected function buildCustomEditFields($object) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$uri_instructions = null;
|
||||
if ($object->isBuiltin()) {
|
||||
$is_builtin = true;
|
||||
$uri_value = (string)$object->getDisplayURI();
|
||||
|
||||
switch ($object->getBuiltinProtocol()) {
|
||||
case PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH:
|
||||
$uri_instructions = pht(
|
||||
" - Configure [[ %s | %s ]] to change the SSH username.\n".
|
||||
" - Configure [[ %s | %s ]] to change the SSH host.\n".
|
||||
" - Configure [[ %s | %s ]] to change the SSH port.",
|
||||
'/config/edit/diffusion.ssh-user/',
|
||||
'diffusion.ssh-user',
|
||||
'/config/edit/diffusion.ssh-host/',
|
||||
'diffusion.ssh-host',
|
||||
'/config/edit/diffusion.ssh-port/',
|
||||
'diffusion.ssh-port');
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$is_builtin = false;
|
||||
$uri_value = $object->getURI();
|
||||
|
||||
if ($object->getRepositoryPHID()) {
|
||||
$repository = $object->getRepository();
|
||||
if ($repository->isGit()) {
|
||||
$uri_instructions = pht(
|
||||
"Provide the URI of a Git repository. It should usually look ".
|
||||
"like one of these examples:\n".
|
||||
"\n".
|
||||
"| Example Git URIs\n".
|
||||
"| -----------------------\n".
|
||||
"| `git@github.com:example/example.git`\n".
|
||||
"| `ssh://user@host.com/git/example.git`\n".
|
||||
"| `https://example.com/repository.git`");
|
||||
} else if ($repository->isHg()) {
|
||||
$uri_instructions = pht(
|
||||
"Provide the URI of a Mercurial repository. It should usually ".
|
||||
"look like one of these examples:\n".
|
||||
"\n".
|
||||
"| Example Mercurial URIs\n".
|
||||
"|-----------------------\n".
|
||||
"| `ssh://hg@bitbucket.org/example/repository`\n".
|
||||
"| `https://bitbucket.org/example/repository`");
|
||||
} else if ($repository->isSVN()) {
|
||||
$uri_instructions = pht(
|
||||
"Provide the **Repository Root** of a Subversion repository. ".
|
||||
"You can identify this by running `svn info` in a working ".
|
||||
"copy. It should usually look like one of these examples:\n".
|
||||
"\n".
|
||||
"| Example Subversion URIs\n".
|
||||
"|-----------------------\n".
|
||||
"| `http://svn.example.org/svnroot/`\n".
|
||||
"| `svn+ssh://svn.example.com/svnroot/`\n".
|
||||
"| `svn://svn.example.net/svnroot/`\n\n".
|
||||
"You **MUST** specify the root of the repository, not a ".
|
||||
"subdirectory.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
id(new PhabricatorHandlesEditField())
|
||||
->setKey('repository')
|
||||
|
@ -104,12 +165,14 @@ final class DiffusionURIEditEngine
|
|||
id(new PhabricatorTextEditField())
|
||||
->setKey('uri')
|
||||
->setLabel(pht('URI'))
|
||||
->setIsRequired(true)
|
||||
->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_URI)
|
||||
->setDescription(pht('The repository URI.'))
|
||||
->setConduitDescription(pht('Change the repository URI.'))
|
||||
->setConduitTypeDescription(pht('New repository URI.'))
|
||||
->setValue($object->getURI()),
|
||||
->setIsRequired(!$is_builtin)
|
||||
->setIsLocked($is_builtin)
|
||||
->setValue($uri_value)
|
||||
->setControlInstructions($uri_instructions),
|
||||
id(new PhabricatorSelectEditField())
|
||||
->setKey('io')
|
||||
->setLabel(pht('I/O Type'))
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
final class DiffusionURIEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
private $repository;
|
||||
private $repositoryPHID;
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
@ -70,7 +73,42 @@ final class DiffusionURIEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorRepositoryURITransaction::TYPE_URI:
|
||||
if (!$this->getIsNewObject()) {
|
||||
$old_uri = $object->getEffectiveURI();
|
||||
} else {
|
||||
$old_uri = null;
|
||||
}
|
||||
|
||||
$object->setURI($xaction->getNewValue());
|
||||
|
||||
// If we've changed the domain or protocol of the URI, remove the
|
||||
// current credential. This improves behavior in several cases:
|
||||
|
||||
// If a user switches between protocols with different credential
|
||||
// types, like HTTP and SSH, the old credential won't be valid anyway.
|
||||
// It's cleaner to remove it than leave a bad credential in place.
|
||||
|
||||
// If a user switches hosts, the old credential is probably not
|
||||
// correct (and potentially confusing/misleading). Removing it forces
|
||||
// users to double check that they have the correct credentials.
|
||||
|
||||
// If an attacker can't see a symmetric credential like a username and
|
||||
// password, they could still potentially capture it by changing the
|
||||
// host for a URI that uses it to `evil.com`, a server they control,
|
||||
// then observing the requests. Removing the credential prevents this
|
||||
// kind of escalation.
|
||||
|
||||
// Since port and path changes are less likely to fall among these
|
||||
// cases, they don't trigger a credential wipe.
|
||||
|
||||
$new_uri = $object->getEffectiveURI();
|
||||
if ($old_uri) {
|
||||
$new_proto = ($old_uri->getProtocol() != $new_uri->getProtocol());
|
||||
$new_domain = ($old_uri->getDomain() != $new_uri->getDomain());
|
||||
if ($new_proto || $new_domain) {
|
||||
$object->setCredentialPHID(null);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PhabricatorRepositoryURITransaction::TYPE_IO:
|
||||
$object->setIOType($xaction->getNewValue());
|
||||
|
@ -80,6 +118,7 @@ final class DiffusionURIEditor
|
|||
break;
|
||||
case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY:
|
||||
$object->setRepositoryPHID($xaction->getNewValue());
|
||||
$object->attachRepository($this->repository);
|
||||
break;
|
||||
case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL:
|
||||
$object->setCredentialPHID($xaction->getNewValue());
|
||||
|
@ -116,6 +155,9 @@ final class DiffusionURIEditor
|
|||
|
||||
switch ($type) {
|
||||
case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY:
|
||||
// Save this, since we need it to validate TYPE_IO transactions.
|
||||
$this->repositoryPHID = $object->getRepositoryPHID();
|
||||
|
||||
$missing = $this->validateIsEmptyTextField(
|
||||
$object->getRepositoryPHID(),
|
||||
$xactions);
|
||||
|
@ -173,6 +215,9 @@ final class DiffusionURIEditor
|
|||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->repository = $repository;
|
||||
$this->repositoryPHID = $repository_phid;
|
||||
}
|
||||
break;
|
||||
case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL:
|
||||
|
@ -184,6 +229,11 @@ final class DiffusionURIEditor
|
|||
continue;
|
||||
}
|
||||
|
||||
// Anyone who can edit a URI can remove the credential.
|
||||
if ($credential_phid === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$credential = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($credential_phid))
|
||||
|
@ -275,7 +325,7 @@ final class DiffusionURIEditor
|
|||
if ($no_observers || $no_readwrite) {
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($object->getRepositoryPHID()))
|
||||
->withPHIDs(array($this->repositoryPHID))
|
||||
->needURIs(true)
|
||||
->executeOne();
|
||||
$uris = $repository->getURIs();
|
||||
|
@ -365,9 +415,69 @@ final class DiffusionURIEditor
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PhabricatorRepositoryURITransaction::TYPE_DISABLE:
|
||||
$old = $object->getIsDisabled();
|
||||
foreach ($xactions as $xaction) {
|
||||
$new = $xaction->getNewValue();
|
||||
|
||||
if ($old == $new) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$object->isBuiltin()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid'),
|
||||
pht('You can not manually disable builtin URIs.'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
protected function applyFinalEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
// Synchronize the repository state based on the presence of an "Observe"
|
||||
// URI.
|
||||
$repository = $object->getRepository();
|
||||
|
||||
$uris = id(new PhabricatorRepositoryURIQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withRepositories(array($repository))
|
||||
->execute();
|
||||
|
||||
$observe_uri = null;
|
||||
foreach ($uris as $uri) {
|
||||
if ($uri->getIoType() != PhabricatorRepositoryURI::IO_OBSERVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$observe_uri = $uri;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($observe_uri) {
|
||||
$repository
|
||||
->setHosted(false)
|
||||
->setDetail('remote-uri', (string)$observe_uri->getEffectiveURI())
|
||||
->setCredentialPHID($observe_uri->getCredentialPHID());
|
||||
} else {
|
||||
$repository
|
||||
->setHosted(true)
|
||||
->setDetail('remote-uri', null)
|
||||
->setCredentialPHID(null);
|
||||
}
|
||||
|
||||
$repository->save();
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -172,14 +172,7 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
|
||||
if ($this->isInitialImport($all_updates)) {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$repository->openTransaction();
|
||||
$repository->beginReadLocking();
|
||||
$repository = $repository->reload();
|
||||
$repository->setDetail('importing', true);
|
||||
$repository->save();
|
||||
$repository->endReadLocking();
|
||||
$repository->saveTransaction();
|
||||
$repository->markImporting();
|
||||
}
|
||||
|
||||
if ($this->emailPHIDs) {
|
||||
|
@ -1244,7 +1237,7 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
$commit_count++;
|
||||
}
|
||||
|
||||
if ($commit_count <= 7) {
|
||||
if ($commit_count <= PhabricatorRepository::IMPORT_THRESHOLD) {
|
||||
// If this pushes a very small number of commits, assume it's an
|
||||
// initial commit or stack of a few initial commits.
|
||||
return false;
|
||||
|
|
|
@ -16,6 +16,18 @@ final class DiffusionRepositoryURIsIndexEngineExtension
|
|||
public function indexObject(
|
||||
PhabricatorIndexEngine $engine,
|
||||
$object) {
|
||||
|
||||
// Reload the repository to pick up URIs, which we need in order to update
|
||||
// the URI index.
|
||||
$object = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($object->getPHID()))
|
||||
->needURIs(true)
|
||||
->executeOne();
|
||||
if (!$object) {
|
||||
return;
|
||||
}
|
||||
|
||||
$object->updateURIIndex();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionDaemonLockException extends Exception {}
|
|
@ -13,6 +13,30 @@ final class DiffusionRepositoryActionsManagementPanel
|
|||
return 1100;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$has_any =
|
||||
$repository->getDetail('herald-disabled') ||
|
||||
$repository->getDetail('disable-autoclose');
|
||||
|
||||
// NOTE: Any value here really means something is disabled, so try to
|
||||
// hint that a little bit with the icon.
|
||||
|
||||
if ($has_any) {
|
||||
return 'fa-comment-o';
|
||||
} else {
|
||||
return 'fa-commenting grey';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'publish',
|
||||
'autoclose',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -22,7 +46,7 @@ final class DiffusionRepositoryActionsManagementPanel
|
|||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$actions_uri = $repository->getPathURI('edit/actions/');
|
||||
$actions_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
id(new PhabricatorActionView())
|
||||
|
|
|
@ -13,6 +13,39 @@ final class DiffusionRepositoryAutomationManagementPanel
|
|||
return 800;
|
||||
}
|
||||
|
||||
public function shouldEnableForRepository(
|
||||
PhabricatorRepository $repository) {
|
||||
return $repository->isGit();
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'automationBlueprintPHIDs',
|
||||
);
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
if (!$repository->canPerformAutomation()) {
|
||||
return 'fa-truck grey';
|
||||
}
|
||||
|
||||
$blueprint_phids = $repository->getAutomationBlueprintPHIDs();
|
||||
if (!$blueprint_phids) {
|
||||
return 'fa-truck grey';
|
||||
}
|
||||
|
||||
$is_authorized = DrydockAuthorizationQuery::isFullyAuthorized(
|
||||
$repository->getPHID(),
|
||||
$blueprint_phids);
|
||||
if (!$is_authorized) {
|
||||
return 'fa-exclamation-triangle yellow';
|
||||
}
|
||||
|
||||
return 'fa-truck';
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -24,7 +57,7 @@ final class DiffusionRepositoryAutomationManagementPanel
|
|||
|
||||
$can_test = $can_edit && $repository->canPerformAutomation();
|
||||
|
||||
$automation_uri = $repository->getPathURI('edit/automation/');
|
||||
$automation_uri = $this->getEditPageURI();
|
||||
$test_uri = $repository->getPathURI('edit/testautomation/');
|
||||
|
||||
return array(
|
||||
|
|
|
@ -13,6 +13,26 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
return 100;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
if (!$repository->isTracked()) {
|
||||
return 'fa-ban indigo';
|
||||
} else {
|
||||
return 'fa-code';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'name',
|
||||
'callsign',
|
||||
'shortName',
|
||||
'description',
|
||||
'projectPHIDs',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -22,10 +42,10 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$edit_uri = $repository->getPathURI('manage/');
|
||||
$edit_uri = $this->getEditPageURI();
|
||||
$activate_uri = $repository->getPathURI('edit/activate/');
|
||||
$delete_uri = $repository->getPathURI('edit/delete/');
|
||||
$encoding_uri = $repository->getPathURI('edit/encoding/');
|
||||
$encoding_uri = $this->getEditPageURI('encoding');
|
||||
$dangerous_uri = $repository->getPathURI('edit/dangerous/');
|
||||
|
||||
if ($repository->isTracked()) {
|
||||
|
@ -84,7 +104,38 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
public function buildManagementPanelContent() {
|
||||
$result = array();
|
||||
|
||||
$result[] = $this->newBox(pht('Repository Basics'), $this->buildBasics());
|
||||
$basics = $this->newBox(pht('Repository Basics'), $this->buildBasics());
|
||||
|
||||
$repository = $this->getRepository();
|
||||
$is_new = $repository->isNewlyInitialized();
|
||||
if ($is_new) {
|
||||
$messages = array();
|
||||
|
||||
$messages[] = pht(
|
||||
'This newly created repository is not active yet. Configure policies, '.
|
||||
'options, and URIs. When ready, %s the repository.',
|
||||
phutil_tag('strong', array(), pht('Activate')));
|
||||
|
||||
if ($repository->isHosted()) {
|
||||
$messages[] = pht(
|
||||
'If activated now, this repository will become a new hosted '.
|
||||
'repository. To observe an existing repository instead, configure '.
|
||||
'it in the %s panel.',
|
||||
phutil_tag('strong', array(), pht('URIs')));
|
||||
} else {
|
||||
$messages[] = pht(
|
||||
'If activated now, this repository will observe an existing remote '.
|
||||
'repository and begin importing changes.');
|
||||
}
|
||||
|
||||
$info_view = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->setErrors($messages);
|
||||
|
||||
$basics->setInfoView($info_view);
|
||||
}
|
||||
|
||||
$result[] = $basics;
|
||||
|
||||
$description = $this->buildDescription();
|
||||
if ($description) {
|
||||
|
|
|
@ -13,6 +13,34 @@ final class DiffusionRepositoryBranchesManagementPanel
|
|||
return 1000;
|
||||
}
|
||||
|
||||
public function shouldEnableForRepository(
|
||||
PhabricatorRepository $repository) {
|
||||
return ($repository->isGit() || $repository->isHg());
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$has_any =
|
||||
$repository->getDetail('default-branch') ||
|
||||
$repository->getDetail('branch-filter') ||
|
||||
$repository->getDetail('close-commits-filter');
|
||||
|
||||
if ($has_any) {
|
||||
return 'fa-code-fork';
|
||||
} else {
|
||||
return 'fa-code-fork grey';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'defaultBranch',
|
||||
'trackOnly',
|
||||
'autocloseOnly',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -22,7 +50,7 @@ final class DiffusionRepositoryBranchesManagementPanel
|
|||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$branches_uri = $repository->getPathURI('edit/branches/');
|
||||
$branches_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
id(new PhabricatorActionView())
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryDocumentationManagementPanel
|
||||
extends DiffusionRepositoryManagementPanel {
|
||||
|
||||
const PANELKEY = 'documentation';
|
||||
|
||||
public function getManagementPanelLabel() {
|
||||
return pht('Documentation');
|
||||
}
|
||||
|
||||
public function getManagementPanelOrder() {
|
||||
return 3000;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
return 'fa-book';
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPanelNavigationURI() {
|
||||
return PhabricatorEnv::getDoclink(
|
||||
'Diffusion User Guide: Managing Repositories');
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,10 @@ final class DiffusionRepositoryHistoryManagementPanel
|
|||
return 2000;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
return 'fa-list-ul';
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
return $this->newTimeline();
|
||||
}
|
||||
|
|
|
@ -38,10 +38,19 @@ abstract class DiffusionRepositoryManagementPanel
|
|||
abstract public function getManagementPanelOrder();
|
||||
abstract public function buildManagementPanelContent();
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
return 'fa-pencil';
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function shouldEnableForRepository(
|
||||
PhabricatorRepository $repository) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final protected function newActions() {
|
||||
$actions = $this->buildManagementPanelActions();
|
||||
if (!$actions) {
|
||||
|
@ -98,4 +107,45 @@ abstract class DiffusionRepositoryManagementPanel
|
|||
return $this->controller->newTimeline($this->getRepository());
|
||||
}
|
||||
|
||||
final public function getPanelURI() {
|
||||
$repository = $this->getRepository();
|
||||
$key = $this->getManagementPanelKey();
|
||||
return $repository->getPathURI("manage/{$key}/");
|
||||
}
|
||||
|
||||
final public function newEditEnginePage() {
|
||||
$field_keys = $this->getEditEngineFieldKeys();
|
||||
if (!$field_keys) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$key = $this->getManagementPanelKey();
|
||||
$label = $this->getManagementPanelLabel();
|
||||
$panel_uri = $this->getPanelURI();
|
||||
|
||||
return id(new PhabricatorEditPage())
|
||||
->setKey($key)
|
||||
->setLabel($label)
|
||||
->setViewURI($panel_uri)
|
||||
->setFieldKeys($field_keys);
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function getEditPageURI($page = null) {
|
||||
if ($page === null) {
|
||||
$page = $this->getManagementPanelKey();
|
||||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
$id = $repository->getID();
|
||||
return "/diffusion/edit/{$id}/page/{$page}/";
|
||||
}
|
||||
|
||||
public function getPanelNavigationURI() {
|
||||
return $this->getPanelURI();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,47 @@ final class DiffusionRepositoryPoliciesManagementPanel
|
|||
return 300;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$viewer = $this->getViewer();
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$can_view = PhabricatorPolicyCapability::CAN_VIEW;
|
||||
$can_edit = PhabricatorPolicyCapability::CAN_EDIT;
|
||||
$can_push = DiffusionPushCapability::CAPABILITY;
|
||||
|
||||
$actual_values = array(
|
||||
'spacePHID' => $repository->getSpacePHID(),
|
||||
'view' => $repository->getPolicy($can_view),
|
||||
'edit' => $repository->getPolicy($can_edit),
|
||||
'push' => $repository->getPolicy($can_push),
|
||||
);
|
||||
|
||||
$default = PhabricatorRepository::initializeNewRepository(
|
||||
$viewer);
|
||||
|
||||
$default_values = array(
|
||||
'spacePHID' => $default->getSpacePHID(),
|
||||
'view' => $default->getPolicy($can_view),
|
||||
'edit' => $default->getPolicy($can_edit),
|
||||
'push' => $default->getPolicy($can_push),
|
||||
);
|
||||
|
||||
if ($actual_values === $default_values) {
|
||||
return 'fa-lock grey';
|
||||
} else {
|
||||
return 'fa-lock';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'policy.view',
|
||||
'policy.edit',
|
||||
'spacePHID',
|
||||
'policy.push',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -22,7 +63,7 @@ final class DiffusionRepositoryPoliciesManagementPanel
|
|||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$edit_uri = $repository->getPathURI('manage/');
|
||||
$edit_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
id(new PhabricatorActionView())
|
||||
|
|
|
@ -13,6 +13,30 @@ final class DiffusionRepositoryStagingManagementPanel
|
|||
return 700;
|
||||
}
|
||||
|
||||
public function shouldEnableForRepository(
|
||||
PhabricatorRepository $repository) {
|
||||
return $repository->isGit();
|
||||
}
|
||||
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$staging_uri = $repository->getStagingURI();
|
||||
|
||||
if ($staging_uri) {
|
||||
return 'fa-upload';
|
||||
} else {
|
||||
return 'fa-upload grey';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'stagingAreaURI',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -22,7 +46,7 @@ final class DiffusionRepositoryStagingManagementPanel
|
|||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$staging_uri = $repository->getPathURI('edit/staging/');
|
||||
$staging_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
id(new PhabricatorActionView())
|
||||
|
|
|
@ -13,6 +13,21 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
return 200;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
// TODO: We could try to show a warning icon in more cases, but just
|
||||
// raise in the most serious cases for now.
|
||||
$messages = $this->loadStatusMessages($repository);
|
||||
|
||||
$raw_error = $this->buildRepositoryRawError($repository, $messages);
|
||||
if ($raw_error) {
|
||||
return 'fa-exclamation-triangle red';
|
||||
}
|
||||
|
||||
return 'fa-check grey';
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -46,9 +61,7 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
pht('Update Frequency'),
|
||||
$this->buildRepositoryUpdateInterval($repository));
|
||||
|
||||
$messages = id(new PhabricatorRepositoryStatusMessage())
|
||||
->loadAllWhere('repositoryID = %d', $repository->getID());
|
||||
$messages = mpull($messages, null, 'getStatusType');
|
||||
$messages = $this->loadStatusMessages($repository);
|
||||
|
||||
$status = $this->buildRepositoryStatus($repository, $messages);
|
||||
$raw_error = $this->buildRepositoryRawError($repository, $messages);
|
||||
|
@ -122,7 +135,12 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
}
|
||||
|
||||
if ($repository->isHosted()) {
|
||||
if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) {
|
||||
$proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS;
|
||||
$proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP;
|
||||
$can_http = $repository->canServeProtocol($proto_http, false) ||
|
||||
$repository->canServeProtocol($proto_https, false);
|
||||
|
||||
if ($can_http) {
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$binaries[] = 'git-http-backend';
|
||||
|
@ -138,7 +156,12 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) {
|
||||
|
||||
|
||||
$proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH;
|
||||
$can_ssh = $repository->canServeProtocol($proto_ssh, false);
|
||||
|
||||
if ($can_ssh) {
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$binaries[] = 'git-receive-pack';
|
||||
|
@ -469,5 +492,22 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
return $raw_message;
|
||||
}
|
||||
|
||||
private function loadStatusMessages(PhabricatorRepository $repository) {
|
||||
$messages = id(new PhabricatorRepositoryStatusMessage())
|
||||
->loadAllWhere('repositoryID = %d', $repository->getID());
|
||||
$messages = mpull($messages, null, 'getStatusType');
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
private function getEnvConfigLink() {
|
||||
$config_href = '/config/edit/environment.append-paths/';
|
||||
return phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $config_href,
|
||||
),
|
||||
'environment.append-paths');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,18 @@ final class DiffusionRepositoryStorageManagementPanel
|
|||
return 600;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
if ($repository->getAlmanacServicePHID()) {
|
||||
return 'fa-sitemap';
|
||||
} else if ($repository->isHosted()) {
|
||||
return 'fa-folder';
|
||||
} else {
|
||||
return 'fa-download';
|
||||
}
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
return array(
|
||||
$this->buildStorageStatusPanel(),
|
||||
|
@ -28,7 +40,7 @@ final class DiffusionRepositoryStorageManagementPanel
|
|||
->setViewer($viewer);
|
||||
|
||||
if ($repository->usesLocalWorkingCopy()) {
|
||||
$storage_path = $repository->getHumanReadableDetail('local-path');
|
||||
$storage_path = $repository->getLocalPath();
|
||||
} else {
|
||||
$storage_path = phutil_tag('em', array(), pht('No Local Working Copy'));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositorySubversionManagementPanel
|
||||
extends DiffusionRepositoryManagementPanel {
|
||||
|
||||
const PANELKEY = 'subversion';
|
||||
|
||||
public function getManagementPanelLabel() {
|
||||
return pht('Subversion');
|
||||
}
|
||||
|
||||
public function getManagementPanelOrder() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
public function shouldEnableForRepository(
|
||||
PhabricatorRepository $repository) {
|
||||
return $repository->isSVN();
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$has_any = (bool)$repository->getDetail('svn-subpath');
|
||||
|
||||
if ($has_any) {
|
||||
return 'fa-database';
|
||||
} else {
|
||||
return 'fa-database grey';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'importOnly',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$subversion_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Properties'))
|
||||
->setHref($subversion_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
|
||||
$default_branch = nonempty(
|
||||
$repository->getHumanReadableDetail('svn-subpath'),
|
||||
phutil_tag('em', array(), pht('Import Entire Repository')));
|
||||
$view->addProperty(pht('Import Only'), $default_branch);
|
||||
|
||||
|
||||
return $this->newBox(pht('Subversion'), $view);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,27 @@ final class DiffusionRepositorySymbolsManagementPanel
|
|||
return 900;
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$has_any =
|
||||
$repository->getSymbolLanguages() ||
|
||||
$repository->getSymbolSources();
|
||||
|
||||
if ($has_any) {
|
||||
return 'fa-link';
|
||||
} else {
|
||||
return 'fa-link grey';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEditEngineFieldKeys() {
|
||||
return array(
|
||||
'symbolLanguages',
|
||||
'symbolRepositoryPHIDs',
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -22,7 +43,7 @@ final class DiffusionRepositorySymbolsManagementPanel
|
|||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$symbols_uri = $repository->getPathURI('edit/symbols/');
|
||||
$symbols_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
id(new PhabricatorActionView())
|
||||
|
|
|
@ -6,11 +6,15 @@ final class DiffusionRepositoryURIsManagementPanel
|
|||
const PANELKEY = 'uris';
|
||||
|
||||
public function getManagementPanelLabel() {
|
||||
return pht('Clone / Fetch / Mirror');
|
||||
return pht('URIs');
|
||||
}
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
return 'fa-cogs';
|
||||
}
|
||||
|
||||
public function getManagementPanelOrder() {
|
||||
return 300;
|
||||
return 400;
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -109,8 +113,44 @@ final class DiffusionRepositoryURIsManagementPanel
|
|||
->setTag('a')
|
||||
->setText(pht('Documentation')));
|
||||
|
||||
$is_new = $repository->isNewlyInitialized();
|
||||
|
||||
$messages = array();
|
||||
if ($repository->isHosted()) {
|
||||
if ($is_new) {
|
||||
$host_message = pht('Phabricator will host this repository.');
|
||||
} else {
|
||||
$host_message = pht('Phabricator is hosting this repository.');
|
||||
}
|
||||
|
||||
$messages[] = array(
|
||||
id(new PHUIIconView())->setIcon('fa-folder'),
|
||||
' ',
|
||||
$host_message,
|
||||
);
|
||||
} else {
|
||||
if ($is_new) {
|
||||
$observe_message = pht(
|
||||
'Phabricator will observe a remote repository.');
|
||||
} else {
|
||||
$observe_message = pht(
|
||||
'This repository is hosted remotely. Phabricator is observing it.');
|
||||
}
|
||||
|
||||
$messages[] = array(
|
||||
id(new PHUIIconView())->setIcon('fa-download'),
|
||||
' ',
|
||||
$observe_message,
|
||||
);
|
||||
}
|
||||
|
||||
$info_view = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->setErrors($messages);
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setInfoView($info_view)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($table);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ abstract class DiffusionCommandEngine extends Phobject {
|
|||
return $this->protocol;
|
||||
}
|
||||
|
||||
public function getDisplayProtocol() {
|
||||
return $this->getProtocol().'://';
|
||||
}
|
||||
|
||||
public function setCredentialPHID($credential_phid) {
|
||||
$this->credentialPHID = $credential_phid;
|
||||
return $this;
|
||||
|
@ -197,34 +201,82 @@ abstract class DiffusionCommandEngine extends Phobject {
|
|||
return $env;
|
||||
}
|
||||
|
||||
protected function isSSHProtocol() {
|
||||
public function isSSHProtocol() {
|
||||
return ($this->getProtocol() == 'ssh');
|
||||
}
|
||||
|
||||
protected function isSVNProtocol() {
|
||||
public function isSVNProtocol() {
|
||||
return ($this->getProtocol() == 'svn');
|
||||
}
|
||||
|
||||
protected function isSVNSSHProtocol() {
|
||||
public function isSVNSSHProtocol() {
|
||||
return ($this->getProtocol() == 'svn+ssh');
|
||||
}
|
||||
|
||||
protected function isHTTPProtocol() {
|
||||
public function isHTTPProtocol() {
|
||||
return ($this->getProtocol() == 'http');
|
||||
}
|
||||
|
||||
protected function isHTTPSProtocol() {
|
||||
public function isHTTPSProtocol() {
|
||||
return ($this->getProtocol() == 'https');
|
||||
}
|
||||
|
||||
protected function isAnyHTTPProtocol() {
|
||||
public function isAnyHTTPProtocol() {
|
||||
return ($this->isHTTPProtocol() || $this->isHTTPSProtocol());
|
||||
}
|
||||
|
||||
protected function isAnySSHProtocol() {
|
||||
public function isAnySSHProtocol() {
|
||||
return ($this->isSSHProtocol() || $this->isSVNSSHProtocol());
|
||||
}
|
||||
|
||||
public function isCredentialSupported() {
|
||||
return ($this->getPassphraseProvidesCredentialType() !== null);
|
||||
}
|
||||
|
||||
public function isCredentialOptional() {
|
||||
if ($this->isAnySSHProtocol()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getPassphraseCredentialLabel() {
|
||||
if ($this->isAnySSHProtocol()) {
|
||||
return pht('SSH Key');
|
||||
}
|
||||
|
||||
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
|
||||
return pht('Password');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPassphraseDefaultCredentialType() {
|
||||
if ($this->isAnySSHProtocol()) {
|
||||
return PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE;
|
||||
}
|
||||
|
||||
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
|
||||
return PassphrasePasswordCredentialType::CREDENTIAL_TYPE;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPassphraseProvidesCredentialType() {
|
||||
if ($this->isAnySSHProtocol()) {
|
||||
return PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
|
||||
}
|
||||
|
||||
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
|
||||
return PassphrasePasswordCredentialType::PROVIDES_TYPE;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getSSHWrapper() {
|
||||
$root = dirname(phutil_get_library_root('phabricator'));
|
||||
return $root.'/bin/ssh-connect';
|
||||
|
|
|
@ -24,8 +24,7 @@ final class DiffusionGitCommandEngine
|
|||
// really silly, but seems like the least damaging approach to
|
||||
// mitigating the issue.
|
||||
|
||||
$root = dirname(phutil_get_library_root('phabricator'));
|
||||
$env['HOME'] = $root.'/support/empty/';
|
||||
$env['HOME'] = PhabricatorEnv::getEmptyCWD();
|
||||
|
||||
if ($this->isAnySSHProtocol()) {
|
||||
$env['GIT_SSH'] = $this->getSSHWrapper();
|
||||
|
|
|
@ -31,6 +31,11 @@ final class DiffusionLowLevelResolveRefsQuery
|
|||
return array();
|
||||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
if (!$repository->hasLocalWorkingCopy()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
switch ($this->getRepository()->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$result = $this->resolveGitRefs();
|
||||
|
|
|
@ -15,7 +15,7 @@ final class DiffusionGitReceivePackSSHWorkflow extends DiffusionGitSSHWorkflow {
|
|||
|
||||
protected function executeRepositoryOperations() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$viewer = $this->getUser();
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
|
||||
// This is a write, and must have write access.
|
||||
|
|
|
@ -185,24 +185,19 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIdentifiers(array($identifier))
|
||||
->needURIs(true)
|
||||
->executeOne();
|
||||
if (!$repository) {
|
||||
throw new Exception(
|
||||
pht('No repository "%s" exists!', $identifier));
|
||||
}
|
||||
|
||||
switch ($repository->getServeOverSSH()) {
|
||||
case PhabricatorRepository::SERVE_READONLY:
|
||||
case PhabricatorRepository::SERVE_READWRITE:
|
||||
// If we have read or read/write access, proceed for now. We will
|
||||
// check write access when the user actually issues a write command.
|
||||
break;
|
||||
case PhabricatorRepository::SERVE_OFF:
|
||||
default:
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This repository ("%s") is not available over SSH.',
|
||||
$repository->getDisplayName()));
|
||||
$protocol = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH;
|
||||
if (!$repository->canServeProtocol($protocol, false)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This repository ("%s") is not available over SSH.',
|
||||
$repository->getDisplayName()));
|
||||
}
|
||||
|
||||
return $repository;
|
||||
|
@ -224,35 +219,27 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
'user account.'));
|
||||
}
|
||||
|
||||
switch ($repository->getServeOverSSH()) {
|
||||
case PhabricatorRepository::SERVE_READONLY:
|
||||
if ($protocol_command !== null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This repository is read-only over SSH (tried to execute '.
|
||||
'protocol command "%s").',
|
||||
$protocol_command));
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht('This repository is read-only over SSH.'));
|
||||
}
|
||||
break;
|
||||
case PhabricatorRepository::SERVE_READWRITE:
|
||||
$can_push = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
DiffusionPushCapability::CAPABILITY);
|
||||
if (!$can_push) {
|
||||
throw new Exception(
|
||||
pht('You do not have permission to push to this repository.'));
|
||||
}
|
||||
break;
|
||||
case PhabricatorRepository::SERVE_OFF:
|
||||
default:
|
||||
// This shouldn't be reachable because we don't get this far if the
|
||||
// repository isn't enabled, but kick them out anyway.
|
||||
$protocol = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH;
|
||||
if ($repository->canServeProtocol($protocol, true)) {
|
||||
$can_push = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
DiffusionPushCapability::CAPABILITY);
|
||||
if (!$can_push) {
|
||||
throw new Exception(
|
||||
pht('This repository is not available over SSH.'));
|
||||
pht('You do not have permission to push to this repository.'));
|
||||
}
|
||||
} else {
|
||||
if ($protocol_command !== null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This repository is read-only over SSH (tried to execute '.
|
||||
'protocol command "%s").',
|
||||
$protocol_command));
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht('This repository is read-only over SSH.'));
|
||||
}
|
||||
}
|
||||
|
||||
$this->hasWriteAccess = true;
|
||||
|
|
|
@ -148,15 +148,25 @@ final class DiffusionSubversionServeSSHWorkflow
|
|||
if ($this->shouldProxy()) {
|
||||
$command = $this->getProxyCommand();
|
||||
$this->isProxying = true;
|
||||
$cwd = null;
|
||||
} else {
|
||||
$command = csprintf(
|
||||
'svnserve -t --tunnel-user=%s',
|
||||
$this->getUser()->getUsername());
|
||||
$cwd = PhabricatorEnv::getEmptyCWD();
|
||||
}
|
||||
|
||||
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
|
||||
$future = new ExecFuture('%C', $command);
|
||||
|
||||
// If we're receiving a commit, svnserve will fail to execute the commit
|
||||
// hook with an unhelpful error if the CWD isn't readable by the user we
|
||||
// are sudoing to. Switch to a readable, empty CWD before running
|
||||
// svnserve. See T10941.
|
||||
if ($cwd !== null) {
|
||||
$future->setCWD($cwd);
|
||||
}
|
||||
|
||||
$this->inProtocol = new DiffusionSubversionWireProtocol();
|
||||
$this->outProtocol = new DiffusionSubversionWireProtocol();
|
||||
|
||||
|
|
131
src/applications/diffusion/view/DiffusionCloneURIView.php
Normal file
131
src/applications/diffusion/view/DiffusionCloneURIView.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
|
||||
final class DiffusionCloneURIView extends AphrontView {
|
||||
|
||||
private $repository;
|
||||
private $repositoryURI;
|
||||
private $displayURI;
|
||||
|
||||
public function setRepository(PhabricatorRepository $repository) {
|
||||
$this->repository = $repository;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRepository() {
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
public function setRepositoryURI(PhabricatorRepositoryURI $repository_uri) {
|
||||
$this->repositoryURI = $repository_uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRepositoryURI() {
|
||||
return $this->repositoryURI;
|
||||
}
|
||||
|
||||
public function setDisplayURI($display_uri) {
|
||||
$this->displayURI = $display_uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDisplayURI() {
|
||||
return $this->displayURI;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('diffusion-icons-css');
|
||||
|
||||
Javelin::initBehavior('select-content');
|
||||
|
||||
$uri_id = celerity_generate_unique_node_id();
|
||||
|
||||
$display = $this->getDisplayURI();
|
||||
|
||||
$input = javelin_tag(
|
||||
'input',
|
||||
array(
|
||||
'id' => $uri_id,
|
||||
'type' => 'text',
|
||||
'value' => $display,
|
||||
'class' => 'diffusion-clone-uri',
|
||||
'readonly' => 'true',
|
||||
));
|
||||
|
||||
$uri = $this->getRepositoryURI();
|
||||
switch ($uri->getEffectiveIOType()) {
|
||||
case PhabricatorRepositoryURI::IO_READ:
|
||||
$io_icon = 'fa-eye';
|
||||
$io_tip = pht('Read-Only');
|
||||
break;
|
||||
case PhabricatorRepositoryURI::IO_READWRITE:
|
||||
$io_icon = 'fa-download';
|
||||
$io_tip = pht('Read / Write');
|
||||
break;
|
||||
default:
|
||||
$io_icon = 'fa-cloud';
|
||||
$io_tip = pht('External');
|
||||
break;
|
||||
}
|
||||
|
||||
$io = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setColor(PHUIButtonView::GREY)
|
||||
->setIcon($io_icon)
|
||||
->setHref('#')
|
||||
->addSigil('select-content')
|
||||
->addSigil('has-tooltip')
|
||||
->setMetadata(
|
||||
array(
|
||||
'tip' => $io_tip,
|
||||
'selectID' => $uri_id,
|
||||
));
|
||||
|
||||
switch ($uri->getEffectiveIOType()) {
|
||||
case PhabricatorRepositoryURI::IO_READ:
|
||||
case PhabricatorRepositoryURI::IO_READWRITE:
|
||||
switch ($uri->getBuiltinProtocol()) {
|
||||
case PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH:
|
||||
$auth_uri = '/settings/panel/ssh/';
|
||||
$auth_tip = pht('Manage SSH Keys');
|
||||
$auth_disabled = false;
|
||||
break;
|
||||
default:
|
||||
$auth_uri = '/settings/panel/vcspassword';
|
||||
$auth_tip = pht('Manage Password');
|
||||
$auth_disabled = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$auth_disabled = true;
|
||||
$auth_tip = pht('External');
|
||||
$auth_uri = '#';
|
||||
break;
|
||||
}
|
||||
|
||||
$credentials = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setColor(PHUIButtonView::GREY)
|
||||
->setIcon('fa-key')
|
||||
->setTooltip($auth_tip)
|
||||
->setHref($auth_uri)
|
||||
->setDisabled($auth_disabled);
|
||||
|
||||
$cells = array();
|
||||
$cells[] = phutil_tag('td', array(), $input);
|
||||
$cells[] = phutil_tag('th', array(), $io);
|
||||
$cells[] = phutil_tag('th', array(), $credentials);
|
||||
|
||||
$row = phutil_tag('tr', array(), $cells);
|
||||
|
||||
return phutil_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'diffusion-clone-uri-table',
|
||||
),
|
||||
$row);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,35 @@ final class DrydockAuthorizationQuery extends DrydockQuery {
|
|||
private $blueprintStates;
|
||||
private $objectStates;
|
||||
|
||||
public static function isFullyAuthorized(
|
||||
$object_phid,
|
||||
array $blueprint_phids) {
|
||||
|
||||
if (!$blueprint_phids) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$authorizations = id(new self())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withObjectPHIDs(array($object_phid))
|
||||
->withBlueprintPHIDs($blueprint_phids)
|
||||
->execute();
|
||||
$authorizations = mpull($authorizations, null, 'getBlueprintPHID');
|
||||
|
||||
foreach ($blueprint_phids as $phid) {
|
||||
$authorization = idx($authorizations, $phid);
|
||||
if (!$authorization) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$authorization->isAuthorized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
|
|
|
@ -93,6 +93,11 @@ final class DrydockAuthorization extends DrydockDAO
|
|||
return idx($map, $state, pht('<Unknown: %s>', $state));
|
||||
}
|
||||
|
||||
public function isAuthorized() {
|
||||
$state = $this->getBlueprintAuthorizationState();
|
||||
return ($state == self::BLUEPRINTAUTH_AUTHORIZED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply external authorization effects after a user chagnes the value of a
|
||||
* blueprint selector control an object.
|
||||
|
|
|
@ -109,6 +109,14 @@ final class PhabricatorEmbedFileRemarkupRule
|
|||
);
|
||||
$image_class = 'phabricator-remarkup-embed-image-full';
|
||||
break;
|
||||
// Displays "full" in normal Remarkup, "wide" in Documents
|
||||
case 'wide':
|
||||
$attrs += array(
|
||||
'src' => $file->getBestURI(),
|
||||
'width' => $file->getImageWidth(),
|
||||
);
|
||||
$image_class = 'phabricator-remarkup-embed-image-wide';
|
||||
break;
|
||||
case 'thumb':
|
||||
default:
|
||||
$preview_key = PhabricatorFileThumbnailTransform::TRANSFORM_PREVIEW;
|
||||
|
|
|
@ -868,23 +868,9 @@ final class ManiphestTransactionEditor
|
|||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_COLUMNS:
|
||||
try {
|
||||
$this->buildMoveTransaction($object, $xaction);
|
||||
|
||||
// Implicilty add the task to any boards that we're moving it
|
||||
// on, since moves on a board the task isn't part of are not
|
||||
// meaningful.
|
||||
$board_phids = ipull($xaction->getNewValue(), 'boardPHID');
|
||||
if ($board_phids) {
|
||||
$results[] = id(new ManiphestTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue(
|
||||
'edge:type',
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
|
||||
->setIgnoreOnNoEffect(true)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => array_fuse($board_phids),
|
||||
));
|
||||
$more_xactions = $this->buildMoveTransaction($object, $xaction);
|
||||
foreach ($more_xactions as $more_xaction) {
|
||||
$results[] = $more_xaction;
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
|
@ -1098,6 +1084,89 @@ final class ManiphestTransactionEditor
|
|||
|
||||
$new = array_values($new);
|
||||
$xaction->setNewValue($new);
|
||||
|
||||
|
||||
$more = array();
|
||||
|
||||
// If we're moving the object into a column and it does not already belong
|
||||
// in the column, add the appropriate board. For normal columns, this
|
||||
// is the board PHID. For proxy columns, it is the proxy PHID, unless the
|
||||
// object is already a member of some descendant of the proxy PHID.
|
||||
|
||||
// The major case where this can happen is moves via the API, but it also
|
||||
// happens when a user drags a task from the "Backlog" to a milestone
|
||||
// column.
|
||||
|
||||
if ($object_phid) {
|
||||
$current_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$object_phid,
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||
$current_phids = array_fuse($current_phids);
|
||||
} else {
|
||||
$current_phids = array();
|
||||
}
|
||||
|
||||
$add_boards = array();
|
||||
foreach ($new as $move) {
|
||||
$column_phid = $move['columnPHID'];
|
||||
$board_phid = $move['boardPHID'];
|
||||
$column = $columns[$column_phid];
|
||||
$proxy_phid = $column->getProxyPHID();
|
||||
|
||||
// If this is a normal column, add the board if the object isn't already
|
||||
// associated.
|
||||
if (!$proxy_phid) {
|
||||
if (!isset($current_phids[$board_phid])) {
|
||||
$add_boards[] = $board_phid;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a proxy column but the object is already associated with
|
||||
// the proxy board, we don't need to do anything.
|
||||
if (isset($current_phids[$proxy_phid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this a proxy column and the object is already associated with some
|
||||
// descendant of the proxy board, we also don't need to do anything.
|
||||
$descendants = id(new PhabricatorProjectQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withAncestorProjectPHIDs(array($proxy_phid))
|
||||
->execute();
|
||||
|
||||
$found_descendant = false;
|
||||
foreach ($descendants as $descendant) {
|
||||
if (isset($current_phids[$descendant->getPHID()])) {
|
||||
$found_descendant = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found_descendant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, we're moving the object to a proxy column which it is not
|
||||
// a member of yet, so add an association to the column's proxy board.
|
||||
|
||||
$add_boards[] = $proxy_phid;
|
||||
}
|
||||
|
||||
if ($add_boards) {
|
||||
$more[] = id(new ManiphestTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue(
|
||||
'edge:type',
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
|
||||
->setIgnoreOnNoEffect(true)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => array_fuse($add_boards),
|
||||
));
|
||||
}
|
||||
|
||||
return $more;
|
||||
}
|
||||
|
||||
private function applyBoardMove($object, array $move) {
|
||||
|
|
|
@ -111,8 +111,11 @@ final class PhabricatorMetaMTAMailBody extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function addPlaintextSection($header, $text) {
|
||||
$this->sections[] = $header."\n".$this->indent($text);
|
||||
public function addPlaintextSection($header, $text, $indent = true) {
|
||||
if ($indent) {
|
||||
$text = $this->indent($text);
|
||||
}
|
||||
$this->sections[] = $header."\n".$text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ final class PhabricatorOwnersPathsController
|
|||
}
|
||||
}
|
||||
|
||||
$repos = mpull($repos, 'getMonogram', 'getPHID');
|
||||
$repos = mpull($repos, 'getDisplayName', 'getPHID');
|
||||
asort($repos);
|
||||
|
||||
$template = new AphrontTypeaheadTemplateView();
|
||||
|
|
|
@ -42,10 +42,50 @@ final class PassphraseCredentialControl extends AphrontFormControl {
|
|||
foreach ($this->options as $option) {
|
||||
$options_map[$option->getPHID()] = pht(
|
||||
'%s %s',
|
||||
'K'.$option->getID(),
|
||||
$option->getMonogram(),
|
||||
$option->getName());
|
||||
}
|
||||
|
||||
// The user editing the form may not have permission to see the current
|
||||
// credential. Populate it into the menu to allow them to save the form
|
||||
// without making any changes.
|
||||
$current_phid = $this->getValue();
|
||||
if (strlen($current_phid) && empty($options_map[$current_phid])) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$user_credential = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($current_phid))
|
||||
->executeOne();
|
||||
if (!$user_credential) {
|
||||
// Pull the credential with the ominipotent viewer so we can look up
|
||||
// the ID and tell if it's restricted or invalid.
|
||||
$omnipotent_credential = id(new PassphraseCredentialQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($current_phid))
|
||||
->executeOne();
|
||||
if ($omnipotent_credential) {
|
||||
$current_name = pht(
|
||||
'%s (Restricted Credential)',
|
||||
$omnipotent_credential->getMonogram());
|
||||
} else {
|
||||
$current_name = pht(
|
||||
'Invalid Credential ("%s")',
|
||||
$current_phid);
|
||||
}
|
||||
} else {
|
||||
$current_name = pht(
|
||||
'%s %s',
|
||||
$user_credential->getMonogram(),
|
||||
$user_credential->getName());
|
||||
}
|
||||
|
||||
$options_map = array(
|
||||
$current_phid => $current_name,
|
||||
) + $options_map;
|
||||
}
|
||||
|
||||
|
||||
$disabled = $this->getDisabled();
|
||||
if ($this->allowNull) {
|
||||
$options_map = array('' => pht('(No Credentials)')) + $options_map;
|
||||
|
|
|
@ -1011,6 +1011,39 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase {
|
|||
$column->getPHID(),
|
||||
);
|
||||
$this->assertColumns($expect, $user, $board, $task);
|
||||
|
||||
|
||||
// Move the task within the "Milestone" column. This should not affect
|
||||
// the projects the task is tagged with. See T10912.
|
||||
$task_a = $task;
|
||||
|
||||
$task_b = $this->newTask($user, array($backlog));
|
||||
$this->moveToColumn($user, $board, $task_b, $backlog, $column);
|
||||
|
||||
$a_options = array(
|
||||
'beforePHID' => $task_b->getPHID(),
|
||||
);
|
||||
|
||||
$b_options = array(
|
||||
'beforePHID' => $task_a->getPHID(),
|
||||
);
|
||||
|
||||
$old_projects = $this->getTaskProjects($task);
|
||||
|
||||
// Move the target task to the top.
|
||||
$this->moveToColumn($user, $board, $task_a, $column, $column, $a_options);
|
||||
$new_projects = $this->getTaskProjects($task_a);
|
||||
$this->assertEqual($old_projects, $new_projects);
|
||||
|
||||
// Move the other task.
|
||||
$this->moveToColumn($user, $board, $task_b, $column, $column, $b_options);
|
||||
$new_projects = $this->getTaskProjects($task_a);
|
||||
$this->assertEqual($old_projects, $new_projects);
|
||||
|
||||
// Move the target task again.
|
||||
$this->moveToColumn($user, $board, $task_a, $column, $column, $a_options);
|
||||
$new_projects = $this->getTaskProjects($task_a);
|
||||
$this->assertEqual($old_projects, $new_projects);
|
||||
}
|
||||
|
||||
public function testColumnExtendedPolicies() {
|
||||
|
|
|
@ -96,32 +96,6 @@ final class PhabricatorProjectMoveController
|
|||
}
|
||||
}
|
||||
|
||||
$proxy = $column->getProxy();
|
||||
if ($proxy) {
|
||||
// We're moving the task into a subproject or milestone column, so add
|
||||
// the subproject or milestone.
|
||||
$add_projects = array($proxy->getPHID());
|
||||
} else if ($project->getHasSubprojects() || $project->getHasMilestones()) {
|
||||
// We're moving the task into the "Backlog" column on the parent project,
|
||||
// so add the parent explicitly. This gets rid of any subproject or
|
||||
// milestone tags.
|
||||
$add_projects = array($project->getPHID());
|
||||
} else {
|
||||
$add_projects = array();
|
||||
}
|
||||
|
||||
if ($add_projects) {
|
||||
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||
|
||||
$xactions[] = id(new ManiphestTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $project_type)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => array_fuse($add_projects),
|
||||
));
|
||||
}
|
||||
|
||||
$editor = id(new ManiphestTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContinueOnMissingFields(true)
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class RepositoryCreateConduitAPIMethod
|
||||
extends RepositoryConduitAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'repository.create';
|
||||
}
|
||||
|
||||
public function getMethodStatus() {
|
||||
return self::METHOD_STATUS_UNSTABLE;
|
||||
}
|
||||
|
||||
public function getMethodStatusDescription() {
|
||||
return pht('Repository methods are new and subject to change.');
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht('Create a new repository.');
|
||||
}
|
||||
|
||||
protected function defineParamTypes() {
|
||||
$vcs_const = $this->formatStringConstants(array('git', 'hg', 'svn'));
|
||||
|
||||
return array(
|
||||
'name' => 'required string',
|
||||
'vcs' => 'required '.$vcs_const,
|
||||
'callsign' => 'required string',
|
||||
'description' => 'optional string',
|
||||
'encoding' => 'optional string',
|
||||
'tracking' => 'optional bool',
|
||||
'uri' => 'required string',
|
||||
'credentialPHID' => 'optional string',
|
||||
'svnSubpath' => 'optional string',
|
||||
'branchFilter' => 'optional list<string>',
|
||||
'closeCommitsFilter' => 'optional list<string>',
|
||||
'pullFrequency' => 'optional int',
|
||||
'defaultBranch' => 'optional string',
|
||||
'heraldEnabled' => 'optional bool, default = true',
|
||||
'autocloseEnabled' => 'optional bool, default = true',
|
||||
'svnUUID' => 'optional string',
|
||||
);
|
||||
}
|
||||
|
||||
protected function defineReturnType() {
|
||||
return 'nonempty dict';
|
||||
}
|
||||
|
||||
protected function defineErrorTypes() {
|
||||
return array(
|
||||
'ERR-DUPLICATE' => pht('Duplicate repository callsign.'),
|
||||
'ERR-BAD-CALLSIGN' => pht(
|
||||
'Callsign is required and must be ALL UPPERCASE LETTERS.'),
|
||||
'ERR-UNKNOWN-REPOSITORY-VCS' => pht('Unknown repository VCS type.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$application = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withClasses(array('PhabricatorDiffusionApplication'))
|
||||
->executeOne();
|
||||
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$request->getUser(),
|
||||
$application,
|
||||
DiffusionCreateRepositoriesCapability::CAPABILITY);
|
||||
|
||||
// TODO: This has some duplication with (and lacks some of the validation
|
||||
// of) the web workflow; refactor things so they can share more code as this
|
||||
// stabilizes. Specifically, this should move to transactions since they
|
||||
// work properly now.
|
||||
|
||||
$repository = PhabricatorRepository::initializeNewRepository(
|
||||
$request->getUser());
|
||||
|
||||
$repository->setName($request->getValue('name'));
|
||||
|
||||
$callsign = $request->getValue('callsign');
|
||||
if (!preg_match('/^[A-Z]+\z/', $callsign)) {
|
||||
throw new ConduitException('ERR-BAD-CALLSIGN');
|
||||
}
|
||||
$repository->setCallsign($callsign);
|
||||
|
||||
$local_path = PhabricatorEnv::getEnvConfig(
|
||||
'repository.default-local-path');
|
||||
|
||||
$local_path = rtrim($local_path, '/');
|
||||
$local_path = $local_path.'/'.$callsign.'/';
|
||||
|
||||
$vcs = $request->getValue('vcs');
|
||||
|
||||
$map = array(
|
||||
'git' => PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
|
||||
'hg' => PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
|
||||
'svn' => PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
|
||||
);
|
||||
if (empty($map[$vcs])) {
|
||||
throw new ConduitException('ERR-UNKNOWN-REPOSITORY-VCS');
|
||||
}
|
||||
$repository->setVersionControlSystem($map[$vcs]);
|
||||
|
||||
$repository->setCredentialPHID($request->getValue('credentialPHID'));
|
||||
|
||||
$remote_uri = $request->getValue('uri');
|
||||
PhabricatorRepository::assertValidRemoteURI($remote_uri);
|
||||
|
||||
$details = array(
|
||||
'encoding' => $request->getValue('encoding'),
|
||||
'description' => $request->getValue('description'),
|
||||
'tracking-enabled' => (bool)$request->getValue('tracking', true),
|
||||
'remote-uri' => $remote_uri,
|
||||
'local-path' => $local_path,
|
||||
'branch-filter' => array_fill_keys(
|
||||
$request->getValue('branchFilter', array()),
|
||||
true),
|
||||
'close-commits-filter' => array_fill_keys(
|
||||
$request->getValue('closeCommitsFilter', array()),
|
||||
true),
|
||||
'pull-frequency' => $request->getValue('pullFrequency'),
|
||||
'default-branch' => $request->getValue('defaultBranch'),
|
||||
'herald-disabled' => !$request->getValue('heraldEnabled', true),
|
||||
'svn-subpath' => $request->getValue('svnSubpath'),
|
||||
'disable-autoclose' => !$request->getValue('autocloseEnabled', true),
|
||||
);
|
||||
|
||||
foreach ($details as $key => $value) {
|
||||
$repository->setDetail($key, $value);
|
||||
}
|
||||
|
||||
try {
|
||||
$repository->save();
|
||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||
throw new ConduitException('ERR-DUPLICATE');
|
||||
}
|
||||
|
||||
return $repository->toDictionary();
|
||||
}
|
||||
|
||||
}
|
|
@ -354,117 +354,17 @@ final class PhabricatorRepositoryPullLocalDaemon
|
|||
}
|
||||
}
|
||||
|
||||
$service_phids = array();
|
||||
foreach ($repositories as $key => $repository) {
|
||||
$service_phid = $repository->getAlmanacServicePHID();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// If the repository is bound to a service but this host is not a
|
||||
// recognized device, or vice versa, don't pull the repository.
|
||||
$is_cluster_repo = (bool)$service_phid;
|
||||
$is_cluster_device = (bool)$device;
|
||||
if ($is_cluster_repo != $is_cluster_device) {
|
||||
if ($is_cluster_device) {
|
||||
$this->log(
|
||||
pht(
|
||||
'Repository "%s" is not a cluster repository, but the current '.
|
||||
'host is a cluster device ("%s"), so the repository will not '.
|
||||
'be updated on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$device->getName()));
|
||||
} else {
|
||||
$this->log(
|
||||
pht(
|
||||
'Repository "%s" is a cluster repository, but the current '.
|
||||
'host is not a cluster device (it has no device ID), so the '.
|
||||
'repository will not be updated on this host.',
|
||||
$repository->getDisplayName()));
|
||||
}
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
$filter = id(new DiffusionLocalRepositoryFilter())
|
||||
->setViewer($viewer)
|
||||
->setDevice($device)
|
||||
->setRepositories($repositories);
|
||||
|
||||
if ($service_phid) {
|
||||
$service_phids[] = $service_phid;
|
||||
}
|
||||
}
|
||||
$repositories = $filter->execute();
|
||||
|
||||
if ($device) {
|
||||
$device_phid = $device->getPHID();
|
||||
|
||||
if ($service_phids) {
|
||||
// We could include `withDevicePHIDs()` here to pull a smaller result
|
||||
// set, but we can provide more helpful diagnostic messages below if
|
||||
// we fetch a little more data.
|
||||
$services = id(new AlmanacServiceQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($service_phids)
|
||||
->withServiceTypes(
|
||||
array(
|
||||
AlmanacClusterRepositoryServiceType::SERVICETYPE,
|
||||
))
|
||||
->needBindings(true)
|
||||
->execute();
|
||||
$services = mpull($services, null, 'getPHID');
|
||||
} else {
|
||||
$services = array();
|
||||
}
|
||||
|
||||
foreach ($repositories as $key => $repository) {
|
||||
$service_phid = $repository->getAlmanacServicePHID();
|
||||
|
||||
$service = idx($services, $service_phid);
|
||||
if (!$service) {
|
||||
$this->log(
|
||||
pht(
|
||||
'Repository "%s" is on cluster service "%s", but that service '.
|
||||
'could not be loaded, so the repository will not be updated '.
|
||||
'on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$service_phid));
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$bindings = $service->getBindings();
|
||||
$bindings = mgroup($bindings, 'getDevicePHID');
|
||||
$bindings = idx($bindings, $device_phid);
|
||||
if (!$bindings) {
|
||||
$this->log(
|
||||
pht(
|
||||
'Repository "%s" is on cluster service "%s", but that service '.
|
||||
'is not bound to this device ("%s"), so the repository will '.
|
||||
'not be updated on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$service->getName(),
|
||||
$device->getName()));
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$all_disabled = true;
|
||||
foreach ($bindings as $binding) {
|
||||
if (!$binding->getIsDisabled()) {
|
||||
$all_disabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($all_disabled) {
|
||||
$this->log(
|
||||
pht(
|
||||
'Repository "%s" is on cluster service "%s", but the binding '.
|
||||
'between that service and this device ("%s") is disabled, so '.
|
||||
'the not be updated on this host.',
|
||||
$repository->getDisplayName(),
|
||||
$service->getName(),
|
||||
$device->getName()));
|
||||
unset($repositories[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a valid service that is actively bound to the current host
|
||||
// device, so we're good to go.
|
||||
}
|
||||
foreach ($filter->getRejectionReasons() as $reason) {
|
||||
$this->log($reason);
|
||||
}
|
||||
|
||||
// Shuffle the repositories, then re-key the array since shuffle()
|
||||
|
|
|
@ -59,6 +59,14 @@ final class PhabricatorRepositoryURINormalizer extends Phobject {
|
|||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
public static function getAllURITypes() {
|
||||
return array(
|
||||
self::TYPE_GIT,
|
||||
self::TYPE_SVN,
|
||||
self::TYPE_MERCURIAL,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* -( Normalizing URIs )--------------------------------------------------- */
|
||||
|
||||
|
@ -91,6 +99,10 @@ final class PhabricatorRepositoryURINormalizer extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
public function getNormalizedURI() {
|
||||
return $this->getNormalizedDomain().'/'.$this->getNormalizedPath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task normal
|
||||
|
@ -113,11 +125,32 @@ final class PhabricatorRepositoryURINormalizer extends Phobject {
|
|||
// example.
|
||||
|
||||
$matches = null;
|
||||
if (preg_match('@^(diffusion/[A-Z]+)@', $path, $matches)) {
|
||||
if (preg_match('@^(diffusion/(?:[A-Z]+|\d+))@', $path, $matches)) {
|
||||
$path = $matches[1];
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function getNormalizedDomain() {
|
||||
$domain = null;
|
||||
|
||||
$uri = new PhutilURI($this->uri);
|
||||
if ($uri->getProtocol()) {
|
||||
$domain = $uri->getDomain();
|
||||
}
|
||||
|
||||
if (!strlen($domain)) {
|
||||
$uri = new PhutilGitURI($this->uri);
|
||||
$domain = $uri->getDomain();
|
||||
}
|
||||
|
||||
if (!strlen($domain)) {
|
||||
$domain = '<void>';
|
||||
}
|
||||
|
||||
return phutil_utf8_strtolower($domain);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,18 +26,7 @@ final class PhabricatorRepositoryEditor
|
|||
$types[] = PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_NOTIFY;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SSH_KEY;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_HOSTING;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_DANGEROUS;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SLUG;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_SERVICE;
|
||||
|
@ -83,20 +72,8 @@ final class PhabricatorRepositoryEditor
|
|||
return (int)!$object->getDetail('herald-disabled');
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||
return (int)!$object->getDetail('disable-autoclose');
|
||||
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
|
||||
return $object->getDetail('remote-uri');
|
||||
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
|
||||
return $object->getDetail('local-path');
|
||||
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
|
||||
return $object->isHosted();
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
|
||||
return $object->getServeOverHTTP();
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
|
||||
return $object->getServeOverSSH();
|
||||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||
return $object->getPushPolicy();
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
return $object->getCredentialPHID();
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
return $object->shouldAllowDangerousChanges();
|
||||
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||
|
@ -130,19 +107,8 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_UUID:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
|
||||
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
|
||||
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
|
||||
case PhabricatorRepositoryTransaction::TYPE_VCS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
|
||||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
|
||||
|
@ -172,7 +138,15 @@ final class PhabricatorRepositoryEditor
|
|||
$object->setVersionControlSystem($xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
|
||||
$object->setDetail('tracking-enabled', $xaction->getNewValue());
|
||||
$active = $xaction->getNewValue();
|
||||
|
||||
// The first time a repository is activated, clear the "new repository"
|
||||
// flag so we stop showing setup hints.
|
||||
if ($active) {
|
||||
$object->setDetail('newly-initialized', false);
|
||||
}
|
||||
|
||||
$object->setDetail('tracking-enabled', $active);
|
||||
break;
|
||||
case PhabricatorRepositoryTransaction::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
|
@ -205,22 +179,8 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||
$object->setDetail('disable-autoclose', (int)!$xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
|
||||
$object->setDetail('remote-uri', $xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
|
||||
$object->setDetail('local-path', $xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
|
||||
return $object->setHosted($xaction->getNewValue());
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
|
||||
return $object->setServeOverHTTP($xaction->getNewValue());
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
|
||||
return $object->setServeOverSSH($xaction->getNewValue());
|
||||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||
return $object->setPushPolicy($xaction->getNewValue());
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
return $object->setCredentialPHID($xaction->getNewValue());
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
$object->setDetail('allow-dangerous-changes', $xaction->getNewValue());
|
||||
return;
|
||||
|
@ -258,27 +218,6 @@ final class PhabricatorRepositoryEditor
|
|||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
// Adjust the object <-> credential edge for this repository.
|
||||
|
||||
$old_phid = $xaction->getOldValue();
|
||||
$new_phid = $xaction->getNewValue();
|
||||
|
||||
$editor = new PhabricatorEdgeEditor();
|
||||
|
||||
$edge_type = PhabricatorObjectUsesCredentialsEdgeType::EDGECONST;
|
||||
$src_phid = $object->getPHID();
|
||||
|
||||
if ($old_phid) {
|
||||
$editor->removeEdge($src_phid, $edge_type, $old_phid);
|
||||
}
|
||||
|
||||
if ($new_phid) {
|
||||
$editor->addEdge($src_phid, $edge_type, $new_phid);
|
||||
}
|
||||
|
||||
$editor->save();
|
||||
break;
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
|
||||
DrydockAuthorization::applyAuthorizationChanges(
|
||||
$this->getActor(),
|
||||
|
@ -304,21 +243,10 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_UUID:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
|
||||
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
|
||||
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
|
||||
case PhabricatorRepositoryTransaction::TYPE_VCS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
|
||||
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
|
||||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SLUG:
|
||||
case PhabricatorRepositoryTransaction::TYPE_SERVICE:
|
||||
|
@ -388,38 +316,6 @@ final class PhabricatorRepositoryEditor
|
|||
}
|
||||
break;
|
||||
|
||||
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
|
||||
foreach ($xactions as $xaction) {
|
||||
$new_uri = $xaction->getNewValue();
|
||||
try {
|
||||
PhabricatorRepository::assertValidRemoteURI($new_uri);
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid'),
|
||||
$ex->getMessage(),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
$ok = PassphraseCredentialControl::validateTransactions(
|
||||
$this->getActor(),
|
||||
$xactions);
|
||||
if (!$ok) {
|
||||
foreach ($xactions as $xaction) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid'),
|
||||
pht(
|
||||
'The selected credential does not exist, or you do not have '.
|
||||
'permission to use it.'),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
|
||||
foreach ($xactions as $xaction) {
|
||||
$old = nonempty($xaction->getOldValue(), array());
|
||||
|
@ -706,7 +602,7 @@ final class PhabricatorRepositoryEditor
|
|||
|
||||
// If the repository does not have a local path yet, assign it one based
|
||||
// on its ID. We can't do this earlier because we won't have an ID yet.
|
||||
$local_path = $object->getDetail('local-path');
|
||||
$local_path = $object->getLocalPath();
|
||||
if (!strlen($local_path)) {
|
||||
$local_key = 'repository.default-local-path';
|
||||
|
||||
|
@ -716,11 +612,22 @@ final class PhabricatorRepositoryEditor
|
|||
$id = $object->getID();
|
||||
$local_path = "{$local_root}/{$id}/";
|
||||
|
||||
$object->setDetail('local-path', $local_path);
|
||||
$object->setLocalPath($local_path);
|
||||
$object->save();
|
||||
}
|
||||
|
||||
if ($this->getIsNewObject()) {
|
||||
// The default state of repositories is to be hosted, if they are
|
||||
// enabled without configuring any "Observe" URIs.
|
||||
$object->setHosted(true);
|
||||
$object->save();
|
||||
|
||||
// Create this repository's builtin URIs.
|
||||
$builtin_uris = $object->newBuiltinURIs();
|
||||
foreach ($builtin_uris as $uri) {
|
||||
$uri->save();
|
||||
}
|
||||
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($this->getActor())
|
||||
->setRepository($object)
|
||||
|
|
|
@ -37,6 +37,33 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
public function discoverCommits() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$lock = $this->newRepositoryLock($repository, 'repo.look', false);
|
||||
|
||||
try {
|
||||
$lock->lock();
|
||||
} catch (PhutilLockException $ex) {
|
||||
throw new DiffusionDaemonLockException(
|
||||
pht(
|
||||
'Another process is currently discovering repository "%s", '.
|
||||
'skipping discovery.',
|
||||
$repository->getDisplayName()));
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->discoverCommitsWithLock();
|
||||
} catch (Exception $ex) {
|
||||
$lock->unlock();
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$lock->unlock();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function discoverCommitsWithLock() {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
switch ($vcs) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
|
@ -52,6 +79,16 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
throw new Exception(pht("Unknown VCS '%s'!", $vcs));
|
||||
}
|
||||
|
||||
if ($this->isInitialImport($refs)) {
|
||||
$this->log(
|
||||
pht(
|
||||
'Discovered more than %s commit(s) in an empty repository, '.
|
||||
'marking repository as importing.',
|
||||
new PhutilNumber(PhabricatorRepository::IMPORT_THRESHOLD)));
|
||||
|
||||
$repository->markImporting();
|
||||
}
|
||||
|
||||
// Clear the working set cache.
|
||||
$this->workingSet = array();
|
||||
|
||||
|
@ -579,4 +616,30 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
PhabricatorWorker::scheduleTask($class, $data);
|
||||
}
|
||||
|
||||
private function isInitialImport(array $refs) {
|
||||
$commit_count = count($refs);
|
||||
|
||||
if ($commit_count <= PhabricatorRepository::IMPORT_THRESHOLD) {
|
||||
// If we fetched a small number of commits, assume it's an initial
|
||||
// commit or a stack of a few initial commits.
|
||||
return false;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$any_commits = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withRepository($repository)
|
||||
->setLimit(1)
|
||||
->execute();
|
||||
|
||||
if ($any_commits) {
|
||||
// If the repository already has commits, this isn't an import.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -51,6 +51,27 @@ abstract class PhabricatorRepositoryEngine extends Phobject {
|
|||
return PhabricatorUser::getOmnipotentUser();
|
||||
}
|
||||
|
||||
protected function newRepositoryLock(
|
||||
PhabricatorRepository $repository,
|
||||
$lock_key,
|
||||
$lock_device_only) {
|
||||
|
||||
$lock_parts = array();
|
||||
$lock_parts[] = $lock_key;
|
||||
$lock_parts[] = $repository->getID();
|
||||
|
||||
if ($lock_device_only) {
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
if ($device) {
|
||||
$lock_parts[] = $device->getID();
|
||||
}
|
||||
}
|
||||
|
||||
$lock_name = implode(':', $lock_parts);
|
||||
return PhabricatorGlobalLock::newLock($lock_name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the "origin" remote exists, and points at the correct URI.
|
||||
*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue