@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

Make callsigns editable on repository basic information

Summary:
Ref T4245. This is a prelude to removing them from the "create" screen.

Currently, if you try to delete the callsign you get an unceremonious database error, but the next diff (or maybe two) will permit that, so I didn't put any "this is required yada yada" text in.

This could also maybe use some big flashing warning lights and a "if you edit this, all your URIs break" but I'll save that for later.

Test Plan: Changed the callsign for a repository.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4245

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

+115 -3
+19
src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php
··· 18 18 $v_name = $repository->getName(); 19 19 $v_desc = $repository->getDetail('description'); 20 20 $v_slug = $repository->getRepositorySlug(); 21 + $v_callsign = $repository->getCallsign(); 21 22 $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( 22 23 $repository->getPHID(), 23 24 PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); 24 25 $e_name = true; 25 26 $e_slug = null; 27 + $e_callsign = null; 26 28 $errors = array(); 27 29 28 30 $validation_exception = null; ··· 31 33 $v_desc = $request->getStr('description'); 32 34 $v_projects = $request->getArr('projectPHIDs'); 33 35 $v_slug = $request->getStr('slug'); 36 + $v_callsign = $request->getStr('callsign'); 34 37 35 38 if (!strlen($v_name)) { 36 39 $e_name = pht('Required'); ··· 47 50 $type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION; 48 51 $type_edge = PhabricatorTransactions::TYPE_EDGE; 49 52 $type_slug = PhabricatorRepositoryTransaction::TYPE_SLUG; 53 + $type_callsign = PhabricatorRepositoryTransaction::TYPE_CALLSIGN; 50 54 51 55 $xactions[] = id(clone $template) 52 56 ->setTransactionType($type_name) ··· 61 65 ->setNewValue($v_slug); 62 66 63 67 $xactions[] = id(clone $template) 68 + ->setTransactionType($type_callsign) 69 + ->setNewValue($v_callsign); 70 + 71 + $xactions[] = id(clone $template) 64 72 ->setTransactionType($type_edge) 65 73 ->setMetadataValue( 66 74 'edge:type', ··· 78 86 try { 79 87 $editor->applyTransactions($repository, $xactions); 80 88 89 + // The preferred edit URI may have changed if the callsign or slug 90 + // were adjusted, so grab a fresh copy. 91 + $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); 92 + 81 93 return id(new AphrontRedirectResponse())->setURI($edit_uri); 82 94 } catch (PhabricatorApplicationTransactionValidationException $ex) { 83 95 $validation_exception = $ex; 84 96 85 97 $e_slug = $ex->getShortMessage($type_slug); 98 + $e_callsign = $ex->getShortMessage($type_callsign); 86 99 } 87 100 } 88 101 } ··· 106 119 ->setLabel(pht('Short Name')) 107 120 ->setValue($v_slug) 108 121 ->setError($e_slug)) 122 + ->appendChild( 123 + id(new AphrontFormTextControl()) 124 + ->setName('callsign') 125 + ->setLabel(pht('Callsign')) 126 + ->setValue($v_callsign) 127 + ->setError($e_callsign)) 109 128 ->appendChild( 110 129 id(new PhabricatorRemarkupControl()) 111 130 ->setUser($viewer)
+49 -1
src/applications/repository/editor/PhabricatorRepositoryEditor.php
··· 45 45 $types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES; 46 46 $types[] = PhabricatorRepositoryTransaction::TYPE_STAGING_URI; 47 47 $types[] = PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS; 48 + $types[] = PhabricatorRepositoryTransaction::TYPE_CALLSIGN; 48 49 49 50 $types[] = PhabricatorTransactions::TYPE_EDGE; 50 51 $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; ··· 110 111 return $object->getDetail('staging-uri'); 111 112 case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS: 112 113 return $object->getDetail('automation.blueprintPHIDs', array()); 114 + case PhabricatorRepositoryTransaction::TYPE_CALLSIGN: 115 + return $object->getCallsign(); 113 116 } 114 117 } 115 118 ··· 148 151 case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS: 149 152 return $xaction->getNewValue(); 150 153 case PhabricatorRepositoryTransaction::TYPE_SLUG: 154 + case PhabricatorRepositoryTransaction::TYPE_CALLSIGN: 151 155 $name = $xaction->getNewValue(); 152 156 if (strlen($name)) { 153 157 return $name; ··· 239 243 $object->setDetail( 240 244 'automation.blueprintPHIDs', 241 245 $xaction->getNewValue()); 246 + return; 247 + case PhabricatorRepositoryTransaction::TYPE_CALLSIGN: 248 + $object->setCallsign($xaction->getNewValue()); 242 249 return; 243 250 case PhabricatorRepositoryTransaction::TYPE_ENCODING: 244 251 // Make sure the encoding is valid by converting to UTF-8. This tests ··· 468 475 } 469 476 470 477 try { 471 - PhabricatorRepository::asssertValidRepositorySlug($new); 478 + PhabricatorRepository::assertValidRepositorySlug($new); 472 479 } catch (Exception $ex) { 473 480 $errors[] = new PhabricatorApplicationTransactionValidationError( 474 481 $type, ··· 495 502 } 496 503 break; 497 504 505 + case PhabricatorRepositoryTransaction::TYPE_CALLSIGN: 506 + foreach ($xactions as $xaction) { 507 + $old = $xaction->getOldValue(); 508 + $new = $xaction->getNewValue(); 509 + 510 + if (!strlen($new)) { 511 + continue; 512 + } 513 + 514 + if ($new === $old) { 515 + continue; 516 + } 517 + 518 + try { 519 + PhabricatorRepository::assertValidCallsign($new); 520 + } catch (Exception $ex) { 521 + $errors[] = new PhabricatorApplicationTransactionValidationError( 522 + $type, 523 + pht('Invalid'), 524 + $ex->getMessage(), 525 + $xaction); 526 + continue; 527 + } 528 + 529 + $other = id(new PhabricatorRepositoryQuery()) 530 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 531 + ->withCallsigns(array($new)) 532 + ->executeOne(); 533 + if ($other && ($other->getID() !== $object->getID())) { 534 + $errors[] = new PhabricatorApplicationTransactionValidationError( 535 + $type, 536 + pht('Duplicate'), 537 + pht( 538 + 'The selected callsign ("%s") is already in use by another '. 539 + 'repository. Choose a unique callsign.', 540 + $new), 541 + $xaction); 542 + continue; 543 + } 544 + } 545 + break; 498 546 } 499 547 500 548 return $errors;
+26 -2
src/applications/repository/storage/PhabricatorRepository.php
··· 317 317 318 318 public static function isValidRepositorySlug($slug) { 319 319 try { 320 - self::asssertValidRepositorySlug($slug); 320 + self::assertValidRepositorySlug($slug); 321 321 return true; 322 322 } catch (Exception $ex) { 323 323 return false; 324 324 } 325 325 } 326 326 327 - public static function asssertValidRepositorySlug($slug) { 327 + public static function assertValidRepositorySlug($slug) { 328 328 if (!strlen($slug)) { 329 329 throw new Exception( 330 330 pht( ··· 388 388 'The name "%s" is not a valid repository short name. Repository '. 389 389 'short names may not contain only numbers.', 390 390 $slug)); 391 + } 392 + } 393 + 394 + public static function assertValidCallsign($callsign) { 395 + if (!strlen($callsign)) { 396 + throw new Exception( 397 + pht( 398 + 'A repository callsign must be at least one character long.')); 399 + } 400 + 401 + if (strlen($callsign) > 32) { 402 + throw new Exception( 403 + pht( 404 + 'The callsign "%s" is not a valid repository callsign. Callsigns '. 405 + 'must be no more than 32 bytes long.', 406 + $callsign)); 407 + } 408 + 409 + if (!preg_match('/^[A-Z]+\z/', $callsign)) { 410 + throw new Exception( 411 + pht( 412 + 'The callsign "%s" is not a valid repository callsign. Callsigns '. 413 + 'may only contain UPPERCASE letters.', 414 + $callsign)); 391 415 } 392 416 } 393 417
+21
src/applications/repository/storage/PhabricatorRepositoryTransaction.php
··· 29 29 const TYPE_SYMBOLS_LANGUAGE = 'repo:symbol-language'; 30 30 const TYPE_STAGING_URI = 'repo:staging-uri'; 31 31 const TYPE_AUTOMATION_BLUEPRINTS = 'repo:automation-blueprints'; 32 + const TYPE_CALLSIGN = 'repo:callsign'; 32 33 33 34 // TODO: Clean up these legacy transaction types. 34 35 const TYPE_SSH_LOGIN = 'repo:ssh-login'; ··· 466 467 new PhutilNumber(count($rem)), 467 468 $this->renderHandleList($rem)); 468 469 } 470 + 471 + case self::TYPE_CALLSIGN: 472 + if ($old === null) { 473 + return pht( 474 + '%s set the callsign for this repository to "%s".', 475 + $this->renderHandleLink($author_phid), 476 + $new); 477 + } else if ($new === null) { 478 + return pht( 479 + '%s removed the callsign ("%s") for this repository.', 480 + $this->renderHandleLink($author_phid), 481 + $old); 482 + } else { 483 + return pht( 484 + '%s changed the callsign for this repository from "%s" to "%s".', 485 + $this->renderHandleLink($author_phid), 486 + $old, 487 + $new); 488 + } 489 + 469 490 } 470 491 471 492 return parent::getTitle();