@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support more transactions types in RepositoryEditEngine

Summary:
Ref T10748. This supports more transaction types in the modern editor and improves validation so Conduit benefits.

You can technically create repositories via `diffusion.repository.edit` now, although they aren't very useful.

Test Plan:
- Used `diffusion.repository.edit` to create and edit repositories.
- Used `/editpro/` to edit repositories.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10748

Differential Revision: https://secure.phabricator.com/D15740

+284 -39
+7 -1
src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
··· 162 162 163 163 $activate = $form->getPage('done') 164 164 ->getControl('activate')->getValue(); 165 + if ($activate == 'start') { 166 + $initial_status = PhabricatorRepository::STATUS_ACTIVE; 167 + } else { 168 + $initial_status = PhabricatorRepository::STATUS_INACTIVE; 169 + } 170 + 165 171 $xactions[] = id(clone $template) 166 172 ->setTransactionType($type_activate) 167 - ->setNewValue(($activate == 'start')); 173 + ->setNewValue($initial_status); 168 174 169 175 if ($service) { 170 176 $xactions[] = id(clone $template)
+8 -1
src/applications/diffusion/controller/DiffusionRepositoryEditActivateController.php
··· 16 16 $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); 17 17 18 18 if ($request->isFormPost()) { 19 + if (!$repository->isTracked()) { 20 + $new_status = PhabricatorRepository::STATUS_ACTIVE; 21 + } else { 22 + $new_status = PhabricatorRepository::STATUS_INACTIVE; 23 + } 24 + 19 25 $xaction = id(new PhabricatorRepositoryTransaction()) 20 26 ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ACTIVATE) 21 - ->setNewValue(!$repository->isTracked()); 27 + ->setNewValue($new_status); 22 28 23 29 $editor = id(new PhabricatorRepositoryEditor()) 24 30 ->setContinueOnNoEffect(true) 31 + ->setContinueOnMissingFields(true) 25 32 ->setContentSourceFromRequest($request) 26 33 ->setActor($viewer) 27 34 ->applyTransactions($repository, array($xaction));
+88
src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php
··· 68 68 } 69 69 70 70 protected function buildCustomEditFields($object) { 71 + $viewer = $this->getViewer(); 72 + 73 + $policies = id(new PhabricatorPolicyQuery()) 74 + ->setViewer($viewer) 75 + ->setObject($object) 76 + ->execute(); 77 + 71 78 return array( 79 + id(new PhabricatorSelectEditField()) 80 + ->setKey('vcs') 81 + ->setLabel(pht('Version Control System')) 82 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_VCS) 83 + ->setIsConduitOnly(true) 84 + ->setIsCopyable(true) 85 + ->setOptions(PhabricatorRepositoryType::getAllRepositoryTypes()) 86 + ->setDescription(pht('Underlying repository version control system.')) 87 + ->setConduitDescription( 88 + pht( 89 + 'Choose which version control system to use when creating a '. 90 + 'repository.')) 91 + ->setConduitTypeDescription(pht('Version control system selection.')) 92 + ->setValue($object->getVersionControlSystem()), 72 93 id(new PhabricatorTextEditField()) 73 94 ->setKey('name') 74 95 ->setLabel(pht('Name')) ··· 78 99 ->setConduitDescription(pht('Rename the repository.')) 79 100 ->setConduitTypeDescription(pht('New repository name.')) 80 101 ->setValue($object->getName()), 102 + id(new PhabricatorTextEditField()) 103 + ->setKey('callsign') 104 + ->setLabel(pht('Callsign')) 105 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_CALLSIGN) 106 + ->setDescription(pht('The repository callsign.')) 107 + ->setConduitDescription(pht('Change the repository callsign.')) 108 + ->setConduitTypeDescription(pht('New repository callsign.')) 109 + ->setValue($object->getCallsign()), 110 + id(new PhabricatorTextEditField()) 111 + ->setKey('shortName') 112 + ->setLabel(pht('Short Name')) 113 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SLUG) 114 + ->setDescription(pht('Short, unique repository name.')) 115 + ->setConduitDescription(pht('Change the repository short name.')) 116 + ->setConduitTypeDescription(pht('New short name for the repository.')) 117 + ->setValue($object->getRepositorySlug()), 118 + id(new PhabricatorRemarkupEditField()) 119 + ->setKey('description') 120 + ->setLabel(pht('Description')) 121 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_DESCRIPTION) 122 + ->setDescription(pht('Repository description.')) 123 + ->setConduitDescription(pht('Change the repository description.')) 124 + ->setConduitTypeDescription(pht('New repository description.')) 125 + ->setValue($object->getDetail('description')), 126 + id(new PhabricatorTextEditField()) 127 + ->setKey('encoding') 128 + ->setLabel(pht('Text Encoding')) 129 + ->setIsCopyable(true) 130 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ENCODING) 131 + ->setDescription(pht('Default text encoding.')) 132 + ->setConduitDescription(pht('Change the default text encoding.')) 133 + ->setConduitTypeDescription(pht('New text encoding.')) 134 + ->setValue($object->getDetail('encoding')), 135 + id(new PhabricatorSelectEditField()) 136 + ->setKey('status') 137 + ->setLabel(pht('Status')) 138 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ACTIVATE) 139 + ->setIsConduitOnly(true) 140 + ->setOptions(PhabricatorRepository::getStatusNameMap()) 141 + ->setDescription(pht('Active or inactive status.')) 142 + ->setConduitDescription(pht('Active or deactivate the repository.')) 143 + ->setConduitTypeDescription(pht('New repository status.')) 144 + ->setValue($object->getStatus()), 145 + id(new PhabricatorTextEditField()) 146 + ->setKey('defaultBranch') 147 + ->setLabel(pht('Default Branch')) 148 + ->setTransactionType( 149 + PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH) 150 + ->setIsCopyable(true) 151 + ->setDescription(pht('Default branch name.')) 152 + ->setConduitDescription(pht('Set the default branch name.')) 153 + ->setConduitTypeDescription(pht('New default branch name.')) 154 + ->setValue($object->getDetail('default-branch')), 155 + id(new PhabricatorPolicyEditField()) 156 + ->setKey('policy.push') 157 + ->setLabel(pht('Push Policy')) 158 + ->setAliases(array('push')) 159 + ->setIsCopyable(true) 160 + ->setCapability(DiffusionPushCapability::CAPABILITY) 161 + ->setPolicies($policies) 162 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY) 163 + ->setDescription( 164 + pht('Controls who can push changes to the repository.')) 165 + ->setConduitDescription( 166 + pht('Change the push policy of the repository.')) 167 + ->setConduitTypeDescription(pht('New policy PHID or constant.')) 168 + ->setValue($object->getPolicy(DiffusionPushCapability::CAPABILITY)), 81 169 ); 82 170 } 83 171
+4 -4
src/applications/repository/constants/PhabricatorRepositoryType.php
··· 7 7 const REPOSITORY_TYPE_MERCURIAL = 'hg'; 8 8 9 9 public static function getAllRepositoryTypes() { 10 - static $map = array( 11 - self::REPOSITORY_TYPE_GIT => 'Git', 12 - self::REPOSITORY_TYPE_SVN => 'Subversion', 13 - self::REPOSITORY_TYPE_MERCURIAL => 'Mercurial', 10 + $map = array( 11 + self::REPOSITORY_TYPE_GIT => pht('Git'), 12 + self::REPOSITORY_TYPE_MERCURIAL => pht('Mercurial'), 13 + self::REPOSITORY_TYPE_SVN => pht('Subversion'), 14 14 ); 15 15 return $map; 16 16 }
+112 -19
src/applications/repository/editor/PhabricatorRepositoryEditor.php
··· 248 248 $object->setCallsign($xaction->getNewValue()); 249 249 return; 250 250 case PhabricatorRepositoryTransaction::TYPE_ENCODING: 251 - // Make sure the encoding is valid by converting to UTF-8. This tests 252 - // that the user has mbstring installed, and also that they didn't type 253 - // a garbage encoding name. Note that we're converting from UTF-8 to 254 - // the target encoding, because mbstring is fine with converting from 255 - // a nonsense encoding. 256 - $encoding = $xaction->getNewValue(); 257 - if (strlen($encoding)) { 258 - try { 259 - phutil_utf8_convert('.', $encoding, 'UTF-8'); 260 - } catch (Exception $ex) { 261 - throw new PhutilProxyException( 262 - pht( 263 - "Error setting repository encoding '%s': %s'", 264 - $encoding, 265 - $ex->getMessage()), 266 - $ex); 267 - } 268 - } 269 - $object->setDetail('encoding', $encoding); 251 + $object->setDetail('encoding', $xaction->getNewValue()); 270 252 break; 271 253 } 272 254 } ··· 456 438 'Some of the selected automation blueprints are invalid '. 457 439 'or restricted: %s.', 458 440 implode(', ', $invalid)), 441 + $xaction); 442 + } 443 + } 444 + break; 445 + 446 + case PhabricatorRepositoryTransaction::TYPE_VCS: 447 + $vcs_map = PhabricatorRepositoryType::getAllRepositoryTypes(); 448 + $current_vcs = $object->getVersionControlSystem(); 449 + 450 + if (!$this->getIsNewObject()) { 451 + foreach ($xactions as $xaction) { 452 + if ($xaction->getNewValue() == $current_vcs) { 453 + continue; 454 + } 455 + 456 + $errors[] = new PhabricatorApplicationTransactionValidationError( 457 + $type, 458 + pht('Immutable'), 459 + pht( 460 + 'You can not change the version control system an existing '. 461 + 'repository uses. It can only be set when a repository is '. 462 + 'first created.'), 463 + $xaction); 464 + } 465 + } else { 466 + $value = $object->getVersionControlSystem(); 467 + foreach ($xactions as $xaction) { 468 + $value = $xaction->getNewValue(); 469 + 470 + if (empty($vcs_map[$value])) { 471 + $errors[] = new PhabricatorApplicationTransactionValidationError( 472 + $type, 473 + pht('Invalid'), 474 + pht( 475 + 'Specified version control system must be a VCS '. 476 + 'recognized by Phabricator: %s.', 477 + implode(', ', array_keys($vcs_map))), 478 + $xaction); 479 + } 480 + } 481 + 482 + if (!strlen($value)) { 483 + $error = new PhabricatorApplicationTransactionValidationError( 484 + $type, 485 + pht('Required'), 486 + pht( 487 + 'When creating a repository, you must specify a valid '. 488 + 'underlying version control system: %s.', 489 + implode(', ', array_keys($vcs_map))), 490 + nonempty(last($xactions), null)); 491 + $error->setIsMissingFieldError(true); 492 + $errors[] = $error; 493 + } 494 + } 495 + break; 496 + 497 + case PhabricatorRepositoryTransaction::TYPE_NAME: 498 + $missing = $this->validateIsEmptyTextField( 499 + $object->getName(), 500 + $xactions); 501 + 502 + if ($missing) { 503 + $error = new PhabricatorApplicationTransactionValidationError( 504 + $type, 505 + pht('Required'), 506 + pht('Repository name is required.'), 507 + nonempty(last($xactions), null)); 508 + 509 + $error->setIsMissingFieldError(true); 510 + $errors[] = $error; 511 + } 512 + break; 513 + 514 + case PhabricatorRepositoryTransaction::TYPE_ACTIVATE: 515 + $status_map = PhabricatorRepository::getStatusMap(); 516 + foreach ($xactions as $xaction) { 517 + $status = $xaction->getNewValue(); 518 + if (empty($status_map[$status])) { 519 + $errors[] = new PhabricatorApplicationTransactionValidationError( 520 + $type, 521 + pht('Invalid'), 522 + pht( 523 + 'Repository status "%s" is not valid.', 524 + $status), 525 + $xaction); 526 + } 527 + } 528 + break; 529 + 530 + case PhabricatorRepositoryTransaction::TYPE_ENCODING: 531 + foreach ($xactions as $xaction) { 532 + // Make sure the encoding is valid by converting to UTF-8. This tests 533 + // that the user has mbstring installed, and also that they didn't 534 + // type a garbage encoding name. Note that we're converting from 535 + // UTF-8 to the target encoding, because mbstring is fine with 536 + // converting from a nonsense encoding. 537 + $encoding = $xaction->getNewValue(); 538 + if (!strlen($encoding)) { 539 + continue; 540 + } 541 + 542 + try { 543 + phutil_utf8_convert('.', $encoding, 'UTF-8'); 544 + } catch (Exception $ex) { 545 + $errors[] = new PhabricatorApplicationTransactionValidationError( 546 + $type, 547 + pht('Invalid'), 548 + pht( 549 + 'Repository encoding "%s" is not valid: %s', 550 + $encoding, 551 + $ex->getMessage()), 459 552 $xaction); 460 553 } 461 554 }
+47 -2
src/applications/repository/storage/PhabricatorRepository.php
··· 46 46 const BECAUSE_BRANCH_NOT_AUTOCLOSE = 'auto/noclose'; 47 47 const BECAUSE_AUTOCLOSE_FORCED = 'auto/forced'; 48 48 49 + const STATUS_ACTIVE = 'active'; 50 + const STATUS_INACTIVE = 'inactive'; 51 + 49 52 protected $name; 50 53 protected $callsign; 51 54 protected $repositorySlug; ··· 132 135 PhabricatorRepositoryRepositoryPHIDType::TYPECONST); 133 136 } 134 137 138 + public static function getStatusMap() { 139 + return array( 140 + self::STATUS_ACTIVE => array( 141 + 'name' => pht('Active'), 142 + 'isTracked' => 1, 143 + ), 144 + self::STATUS_INACTIVE => array( 145 + 'name' => pht('Inactive'), 146 + 'isTracked' => 0, 147 + ), 148 + ); 149 + } 150 + 151 + public static function getStatusNameMap() { 152 + return ipull(self::getStatusMap(), 'name'); 153 + } 154 + 155 + public function getStatus() { 156 + if ($this->isTracked()) { 157 + return self::STATUS_ACTIVE; 158 + } else { 159 + return self::STATUS_INACTIVE; 160 + } 161 + } 162 + 135 163 public function toDictionary() { 136 164 return array( 137 165 'id' => $this->getID(), ··· 146 174 'isActive' => $this->isTracked(), 147 175 'isHosted' => $this->isHosted(), 148 176 'isImporting' => $this->isImporting(), 149 - 'encoding' => $this->getDetail('encoding'), 177 + 'encoding' => $this->getDefaultTextEncoding(), 150 178 'staging' => array( 151 179 'supported' => $this->supportsStaging(), 152 180 'prefix' => 'phabricator', 153 181 'uri' => $this->getStagingURI(), 154 182 ), 155 183 ); 184 + } 185 + 186 + public function getDefaultTextEncoding() { 187 + return $this->getDetail('encoding', 'UTF-8'); 156 188 } 157 189 158 190 public function getMonogram() { ··· 994 1026 } 995 1027 996 1028 public function isTracked() { 997 - return $this->getDetail('tracking-enabled', false); 1029 + $status = $this->getDetail('tracking-enabled'); 1030 + $map = self::getStatusMap(); 1031 + $spec = idx($map, $status); 1032 + 1033 + if (!$spec) { 1034 + if ($status) { 1035 + $status = self::STATUS_ACTIVE; 1036 + } else { 1037 + $status = self::STATUS_INACTIVE; 1038 + } 1039 + $spec = idx($map, $status); 1040 + } 1041 + 1042 + return (bool)idx($spec, 'isTracked', false); 998 1043 } 999 1044 1000 1045 public function getDefaultBranch() {
+18 -12
src/applications/repository/storage/PhabricatorRepositoryTransaction.php
··· 4 4 extends PhabricatorApplicationTransaction { 5 5 6 6 const TYPE_VCS = 'repo:vcs'; 7 - const TYPE_ACTIVATE = 'repo:activate'; 8 - const TYPE_NAME = 'repo:name'; 9 - const TYPE_DESCRIPTION = 'repo:description'; 10 - const TYPE_ENCODING = 'repo:encoding'; 7 + const TYPE_ACTIVATE = 'repo:activate'; 8 + const TYPE_NAME = 'repo:name'; 9 + const TYPE_DESCRIPTION = 'repo:description'; 10 + const TYPE_ENCODING = 'repo:encoding'; 11 11 const TYPE_DEFAULT_BRANCH = 'repo:default-branch'; 12 12 const TYPE_TRACK_ONLY = 'repo:track-only'; 13 13 const TYPE_AUTOCLOSE_ONLY = 'repo:autoclose-only'; 14 14 const TYPE_SVN_SUBPATH = 'repo:svn-subpath'; 15 - const TYPE_UUID = 'repo:uuid'; 16 15 const TYPE_NOTIFY = 'repo:notify'; 17 16 const TYPE_AUTOCLOSE = 'repo:autoclose'; 18 - const TYPE_REMOTE_URI = 'repo:remote-uri'; 19 - const TYPE_LOCAL_PATH = 'repo:local-path'; 20 - const TYPE_HOSTING = 'repo:hosting'; 21 - const TYPE_PROTOCOL_HTTP = 'repo:serve-http'; 22 - const TYPE_PROTOCOL_SSH = 'repo:serve-ssh'; 23 17 const TYPE_PUSH_POLICY = 'repo:push-policy'; 24 - const TYPE_CREDENTIAL = 'repo:credential'; 25 18 const TYPE_DANGEROUS = 'repo:dangerous'; 26 19 const TYPE_SLUG = 'repo:slug'; 27 20 const TYPE_SERVICE = 'repo:service'; ··· 37 30 const TYPE_SSH_KEYFILE = 'repo:ssh-keyfile'; 38 31 const TYPE_HTTP_LOGIN = 'repo:http-login'; 39 32 const TYPE_HTTP_PASS = 'repo:http-pass'; 33 + const TYPE_CREDENTIAL = 'repo:credential'; 34 + const TYPE_PROTOCOL_HTTP = 'repo:serve-http'; 35 + const TYPE_PROTOCOL_SSH = 'repo:serve-ssh'; 36 + const TYPE_HOSTING = 'repo:hosting'; 37 + const TYPE_LOCAL_PATH = 'repo:local-path'; 38 + const TYPE_REMOTE_URI = 'repo:remote-uri'; 39 + const TYPE_UUID = 'repo:uuid'; 40 40 41 41 public function getApplicationName() { 42 42 return 'repository'; ··· 134 134 '%s created this repository.', 135 135 $this->renderHandleLink($author_phid)); 136 136 case self::TYPE_ACTIVATE: 137 - if ($new) { 137 + // TODO: Old versions of this transaction use a boolean value, but 138 + // should be migrated. 139 + $is_deactivate = 140 + (!$new) || 141 + ($new == PhabricatorRepository::STATUS_INACTIVE); 142 + 143 + if (!$is_deactivate) { 138 144 return pht( 139 145 '%s activated this repository.', 140 146 $this->renderHandleLink($author_phid));