@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.

Provide a new "hint" table for weird commits (rewritten, unreadable)

Summary:
Ref T11522. This provides storage for tracking rewritten commits (new feature) and unreadable commits (existing feature, but really hacky).

This doesn't do anything yet, just adds a table and a CLI tool for updating it. I'll document the tool once it works. You just pipe in some JSON, but I need to document the format.

Test Plan:
- Piped JSON for "none", "rewritten" and "unreadable" hints into `bin/repository hint`.
- Examined the database to see that the table was written properly.
- Tried to pipe bad JSON in, invalid hint types, etc. Got reasonable human-readable error messages.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11522

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

+306
+8
resources/sql/autopatches/20160824.repohint.01.hint.sql
··· 1 + CREATE TABLE {$NAMESPACE}_repository.repository_commithint ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + repositoryPHID VARBINARY(64) NOT NULL, 4 + oldCommitIdentifier VARCHAR(40) NOT NULL COLLATE {$COLLATE_TEXT}, 5 + newCommitIdentifier VARCHAR(40) COLLATE {$COLLATE_TEXT}, 6 + hintType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 7 + UNIQUE KEY `key_old` (repositoryPHID, oldCommitIdentifier) 8 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+9
src/__phutil_library_map__.php
··· 612 612 'DiffusionCommitHash' => 'applications/diffusion/data/DiffusionCommitHash.php', 613 613 'DiffusionCommitHeraldField' => 'applications/diffusion/herald/DiffusionCommitHeraldField.php', 614 614 'DiffusionCommitHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionCommitHeraldFieldGroup.php', 615 + 'DiffusionCommitHintQuery' => 'applications/diffusion/query/DiffusionCommitHintQuery.php', 615 616 'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php', 616 617 'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php', 617 618 'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php', ··· 3383 3384 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php', 3384 3385 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php', 3385 3386 'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php', 3387 + 'PhabricatorRepositoryCommitHint' => 'applications/repository/storage/PhabricatorRepositoryCommitHint.php', 3386 3388 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php', 3387 3389 'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php', 3388 3390 'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php', ··· 3403 3405 'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php', 3404 3406 'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php', 3405 3407 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php', 3408 + 'PhabricatorRepositoryManagementHintWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementHintWorkflow.php', 3406 3409 'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php', 3407 3410 'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php', 3408 3411 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', ··· 5104 5107 'DiffusionCommitHash' => 'Phobject', 5105 5108 'DiffusionCommitHeraldField' => 'HeraldField', 5106 5109 'DiffusionCommitHeraldFieldGroup' => 'HeraldFieldGroup', 5110 + 'DiffusionCommitHintQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5107 5111 'DiffusionCommitHookEngine' => 'Phobject', 5108 5112 'DiffusionCommitHookRejectException' => 'Exception', 5109 5113 'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField', ··· 8348 8352 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 8349 8353 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 8350 8354 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', 8355 + 'PhabricatorRepositoryCommitHint' => array( 8356 + 'PhabricatorRepositoryDAO', 8357 + 'PhabricatorPolicyInterface', 8358 + ), 8351 8359 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 8352 8360 'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker', 8353 8361 'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType', ··· 8372 8380 'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 8373 8381 'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 8374 8382 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 8383 + 'PhabricatorRepositoryManagementHintWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 8375 8384 'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 8376 8385 'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 8377 8386 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
+64
src/applications/diffusion/query/DiffusionCommitHintQuery.php
··· 1 + <?php 2 + 3 + final class DiffusionCommitHintQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $repositoryPHIDs; 8 + private $oldCommitIdentifiers; 9 + 10 + public function withIDs(array $ids) { 11 + $this->ids = $ids; 12 + return $this; 13 + } 14 + 15 + public function withRepositoryPHIDs(array $phids) { 16 + $this->repositoryPHIDs = $phids; 17 + return $this; 18 + } 19 + 20 + public function withOldCommitIdentifiers(array $identifiers) { 21 + $this->oldCommitIdentifiers = $identifiers; 22 + return $this; 23 + } 24 + 25 + public function newResultObject() { 26 + return new PhabricatorRepositoryCommitHint(); 27 + } 28 + 29 + protected function loadPage() { 30 + return $this->loadStandardPage($this->newResultObject()); 31 + } 32 + 33 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 34 + $where = parent::buildWhereClauseParts($conn); 35 + 36 + if ($this->ids !== null) { 37 + $where[] = qsprintf( 38 + $conn, 39 + 'id IN (%Ld)', 40 + $this->ids); 41 + } 42 + 43 + if ($this->repositoryPHIDs !== null) { 44 + $where[] = qsprintf( 45 + $conn, 46 + 'reositoryPHID IN (%Ls)', 47 + $this->repositoryPHIDs); 48 + } 49 + 50 + if ($this->oldCommitIdentifiers !== null) { 51 + $where[] = qsprintf( 52 + $conn, 53 + 'oldCommitIdentifier IN (%Ls)', 54 + $this->oldCommitIdentifiers); 55 + } 56 + 57 + return $where; 58 + } 59 + 60 + public function getQueryApplicationClass() { 61 + return 'PhabricatorDiffusionApplication'; 62 + } 63 + 64 + }
+97
src/applications/repository/management/PhabricatorRepositoryManagementHintWorkflow.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryManagementHintWorkflow 4 + extends PhabricatorRepositoryManagementWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this 8 + ->setName('hint') 9 + ->setExamples('**hint** [options] ...') 10 + ->setSynopsis( 11 + pht( 12 + 'Write hints about unusual (rewritten or unreadable) commits.')) 13 + ->setArguments(array()); 14 + } 15 + 16 + public function execute(PhutilArgumentParser $args) { 17 + $viewer = $this->getViewer(); 18 + 19 + echo tsprintf( 20 + "%s\n", 21 + pht('Reading list of hints from stdin...')); 22 + 23 + $hints = file_get_contents('php://stdin'); 24 + if ($hints === false) { 25 + throw new PhutilArgumentUsageException(pht('Failed to read stdin.')); 26 + } 27 + 28 + try { 29 + $hints = phutil_json_decode($hints); 30 + } catch (Exception $ex) { 31 + throw new PhutilArgumentUsageException( 32 + pht( 33 + 'Expected a list of hints in JSON format: %s', 34 + $ex->getMessage())); 35 + } 36 + 37 + $repositories = array(); 38 + foreach ($hints as $idx => $hint) { 39 + if (!is_array($hint)) { 40 + throw new PhutilArgumentUsageException( 41 + pht( 42 + 'Each item in the list of hints should be a JSON object, but '. 43 + 'the item at index "%s" is not.', 44 + $idx)); 45 + } 46 + 47 + try { 48 + PhutilTypeSpec::checkMap( 49 + $hint, 50 + array( 51 + 'repository' => 'string|int', 52 + 'old' => 'string', 53 + 'new' => 'optional string|null', 54 + 'hint' => 'string', 55 + )); 56 + } catch (Exception $ex) { 57 + throw new PhutilArgumentUsageException( 58 + pht( 59 + 'Unexpected hint format at index "%s": %s', 60 + $idx, 61 + $ex->getMessage())); 62 + } 63 + 64 + $repository_identifier = $hint['repository']; 65 + $repository = idx($repositories, $repository_identifier); 66 + if (!$repository) { 67 + $repository = id(new PhabricatorRepositoryQuery()) 68 + ->setViewer($viewer) 69 + ->withIdentifiers(array($repository_identifier)) 70 + ->executeOne(); 71 + if (!$repository) { 72 + throw new PhutilArgumentUsageException( 73 + pht( 74 + 'Repository identifier "%s" (in hint at index "%s") does not '. 75 + 'identify a valid repository.', 76 + $repository_identifier, 77 + $idx)); 78 + } 79 + 80 + $repositories[$repository_identifier] = $repository; 81 + } 82 + 83 + PhabricatorRepositoryCommitHint::updateHint( 84 + $repository->getPHID(), 85 + $hint['old'], 86 + idx($hint, 'new'), 87 + $hint['hint']); 88 + 89 + echo tsprintf( 90 + "%s\n", 91 + pht( 92 + 'Updated hint for "%s".', 93 + $hint['old'])); 94 + } 95 + } 96 + 97 + }
+128
src/applications/repository/storage/PhabricatorRepositoryCommitHint.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryCommitHint 4 + extends PhabricatorRepositoryDAO 5 + implements PhabricatorPolicyInterface { 6 + 7 + protected $repositoryPHID; 8 + protected $oldCommitIdentifier; 9 + protected $newCommitIdentifier; 10 + protected $hintType; 11 + 12 + const HINT_NONE = 'none'; 13 + const HINT_REWRITTEN = 'rewritten'; 14 + const HINT_UNREADABLE = 'unreadable'; 15 + 16 + protected function getConfiguration() { 17 + return array( 18 + self::CONFIG_TIMESTAMPS => false, 19 + self::CONFIG_COLUMN_SCHEMA => array( 20 + 'oldCommitIdentifier' => 'text40', 21 + 'newCommitIdentifier' => 'text40?', 22 + 'hintType' => 'text32', 23 + ), 24 + self::CONFIG_KEY_SCHEMA => array( 25 + 'key_old' => array( 26 + 'columns' => array('repositoryPHID', 'oldCommitIdentifier'), 27 + 'unique' => true, 28 + ), 29 + ), 30 + ) + parent::getConfiguration(); 31 + } 32 + 33 + public static function getAllHintTypes() { 34 + return array( 35 + self::HINT_NONE, 36 + self::HINT_REWRITTEN, 37 + self::HINT_UNREADABLE, 38 + ); 39 + } 40 + 41 + public static function updateHint($repository_phid, $old, $new, $type) { 42 + switch ($type) { 43 + case self::HINT_NONE: 44 + break; 45 + case self::HINT_REWRITTEN: 46 + if (!$new) { 47 + throw new Exception( 48 + pht( 49 + 'When hinting a commit ("%s") as rewritten, you must provide '. 50 + 'the commit it was rewritten into.', 51 + $old)); 52 + } 53 + break; 54 + case self::HINT_UNREADABLE: 55 + if ($new) { 56 + throw new Exception( 57 + pht( 58 + 'When hinting a commit ("%s") as unreadable, you must not '. 59 + 'provide a new commit ("%s").', 60 + $old, 61 + $new)); 62 + } 63 + break; 64 + default: 65 + $all_types = self::getAllHintTypes(); 66 + throw new Exception( 67 + pht( 68 + 'Hint type ("%s") for commit ("%s") is not valid. Valid hints '. 69 + 'are: %s.', 70 + $type, 71 + $old, 72 + implode(', ', $all_types))); 73 + } 74 + 75 + $table = new self(); 76 + $table_name = $table->getTableName(); 77 + $conn = $table->establishConnection('w'); 78 + 79 + if ($type == self::HINT_NONE) { 80 + queryfx( 81 + $conn, 82 + 'DELETE FROM %T WHERE repositoryPHID = %s AND oldCommitIdentifier = %s', 83 + $table_name, 84 + $repository_phid, 85 + $old); 86 + } else { 87 + queryfx( 88 + $conn, 89 + 'INSERT INTO %T 90 + (repositoryPHID, oldCommitIdentifier, newCommitIdentifier, hintType) 91 + VALUES (%s, %s, %ns, %s) 92 + ON DUPLICATE KEY UPDATE 93 + newCommitIdentifier = VALUES(newCommitIdentifier), 94 + hintType = VALUES(hintType)', 95 + $table_name, 96 + $repository_phid, 97 + $old, 98 + $new, 99 + $type); 100 + } 101 + } 102 + 103 + 104 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 105 + 106 + 107 + public function getCapabilities() { 108 + return array( 109 + PhabricatorPolicyCapability::CAN_VIEW, 110 + ); 111 + } 112 + 113 + public function getPolicy($capability) { 114 + switch ($capability) { 115 + case PhabricatorPolicyCapability::CAN_VIEW: 116 + return PhabricatorPolicies::getMostOpenPolicy(); 117 + } 118 + } 119 + 120 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 121 + return false; 122 + } 123 + 124 + public function describeAutomaticCapability($capability) { 125 + return null; 126 + } 127 + 128 + }