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

Add "RepositoryStatusMessage" and detailed information about initilization

Summary:
`RepositoryStatusMessage` is basically a key/value table associated with a repository that I'm using to let the daemons store the most recent event of a given type, so we can easily show it on the status dashboard. I think this will be a lot easier for users to figure out than digging through logfiles.

I'm also going to write the "this needs a pull" status here eventually, for reducing the time lapse between pushes and discovery.

- Add storage for these messages.
- Have the pull engine populate the INIT phase. I'll do the FETCH phase next.
- Update the status readout to show all the various states.

Test Plan: See screenshots.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

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

+213 -34
+10
resources/sql/patches/20131030.repostatusmessage.sql
··· 1 + CREATE TABLE {$NAMESPACE}_repository.repository_statusmessage ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + repositoryID INT UNSIGNED NOT NULL, 4 + statusType VARCHAR(32) NOT NULL COLLATE utf8_bin, 5 + statusCode VARCHAR(32) NOT NULL COLLATE utf8_bin, 6 + parameters LONGTEXT NOT NULL, 7 + epoch INT UNSIGNED NOT NULL, 8 + UNIQUE KEY (repositoryID, statusType) 9 + ) ENGINE=InnoDB, CHARSET utf8; 10 +
+2
src/__phutil_library_map__.php
··· 1665 1665 'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php', 1666 1666 'PhabricatorRepositorySearchEngine' => 'applications/repository/query/PhabricatorRepositorySearchEngine.php', 1667 1667 'PhabricatorRepositoryShortcut' => 'applications/repository/storage/PhabricatorRepositoryShortcut.php', 1668 + 'PhabricatorRepositoryStatusMessage' => 'applications/repository/storage/PhabricatorRepositoryStatusMessage.php', 1668 1669 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php', 1669 1670 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositorySvnCommitMessageParserWorker.php', 1670 1671 'PhabricatorRepositorySymbol' => 'applications/repository/storage/PhabricatorRepositorySymbol.php', ··· 4005 4006 'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4006 4007 'PhabricatorRepositorySearchEngine' => 'PhabricatorApplicationSearchEngine', 4007 4008 'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO', 4009 + 'PhabricatorRepositoryStatusMessage' => 'PhabricatorRepositoryDAO', 4008 4010 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 4009 4011 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 4010 4012 'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO',
+51 -6
src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
··· 565 565 566 566 $view = new PHUIStatusListView(); 567 567 568 + $messages = id(new PhabricatorRepositoryStatusMessage()) 569 + ->loadAllWhere('repositoryID = %d', $repository->getID()); 570 + $messages = mpull($messages, null, 'getStatusType'); 571 + 568 572 if ($repository->isTracked()) { 569 573 $view->addItem( 570 574 id(new PHUIStatusItemView()) ··· 655 659 656 660 if ($repository->usesLocalWorkingCopy()) { 657 661 $local_path = $repository->getLocalPath(); 658 - if (Filesystem::pathExists($local_path)) { 659 - $view->addItem( 660 - id(new PHUIStatusItemView()) 661 - ->setIcon('accept-green') 662 - ->setTarget(pht('Working Copy OK')) 663 - ->setNote(phutil_tag('tt', array(), $local_path))); 662 + $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); 663 + if ($message) { 664 + switch ($message->getStatusCode()) { 665 + case PhabricatorRepositoryStatusMessage::CODE_ERROR: 666 + $view->addItem( 667 + id(new PHUIStatusItemView()) 668 + ->setIcon('warning-red') 669 + ->setTarget(pht('Initialization Error')) 670 + ->setNote($message->getParameter('message'))); 671 + return $view; 672 + case PhabricatorRepositoryStatusMessage::CODE_OKAY: 673 + if (Filesystem::pathExists($local_path)) { 674 + $view->addItem( 675 + id(new PHUIStatusItemView()) 676 + ->setIcon('accept-green') 677 + ->setTarget(pht('Working Copy OK')) 678 + ->setNote(phutil_tag('tt', array(), $local_path))); 679 + } else { 680 + $view->addItem( 681 + id(new PHUIStatusItemView()) 682 + ->setIcon('warning-red') 683 + ->setTarget(pht('Working Copy Error')) 684 + ->setNote( 685 + pht( 686 + 'Working copy %s has been deleted, or is not '. 687 + 'readable by the webserver. Make this directory '. 688 + 'readable. If it has been deleted, the daemons should '. 689 + 'restore it automatically.', 690 + phutil_tag('tt', array(), $local_path)))); 691 + return $view; 692 + } 693 + break; 694 + case PhabricatorRepositoryStatusMessage::CODE_WORKING: 695 + $view->addItem( 696 + id(new PHUIStatusItemView()) 697 + ->setIcon('time-green') 698 + ->setTarget(pht('Initializing Working Copy')) 699 + ->setNote(pht('Daemons are initilizing the working copy.'))); 700 + return $view; 701 + default: 702 + $view->addItem( 703 + id(new PHUIStatusItemView()) 704 + ->setIcon('warning-red') 705 + ->setTarget(pht('Unknown Init Status')) 706 + ->setNote($message->getStatusCode())); 707 + return $view; 708 + } 664 709 } else { 665 710 $view->addItem( 666 711 id(new PHUIStatusItemView())
+76 -28
src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
··· 27 27 $callsign = $repository->getCallsign(); 28 28 29 29 if ($repository->isHosted()) { 30 - $this->log( 30 + $this->skipPull( 31 31 pht( 32 32 'Repository "%s" is hosted, so Phabricator does not pull updates '. 33 33 'for it.', ··· 38 38 switch ($vcs) { 39 39 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 40 40 // We never pull a local copy of Subversion repositories. 41 - $this->log( 42 - "Repository '%s' is a Subversion repository, which does not require ". 43 - "a local working copy to be pulled.", 44 - $callsign); 41 + $this->skipPull( 42 + pht( 43 + "Repository '%s' is a Subversion repository, which does not ". 44 + "require a local working copy to be pulled.", 45 + $callsign)); 45 46 return; 46 47 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: 47 48 $is_git = true; ··· 50 51 $is_hg = true; 51 52 break; 52 53 default: 53 - throw new Exception("Unsupported VCS '{$vcs}'!"); 54 + $this->abortPull(pht('Unknown VCS "%s"!', $vcs)); 54 55 } 55 56 56 57 $callsign = $repository->getCallsign(); 57 58 $local_path = $repository->getLocalPath(); 58 59 if ($local_path === null) { 59 - throw new Exception( 60 - "No local path is configured for repository '{$callsign}'."); 60 + $this->abortPull( 61 + pht( 62 + "No local path is configured for repository '%s'.", 63 + $callsign)); 61 64 } 62 65 63 - $dirname = dirname($local_path); 64 - if (!Filesystem::pathExists($dirname)) { 65 - Filesystem::createDirectory($dirname, 0755, $recursive = true); 66 - } 67 - 68 - if (!Filesystem::pathExists($local_path)) { 69 - $this->log( 70 - "Creating a new working copy for repository '%s'.", 71 - $callsign); 72 - if ($is_git) { 73 - $this->executeGitCreate(); 74 - } else { 75 - $this->executeMercurialCreate(); 66 + try { 67 + $dirname = dirname($local_path); 68 + if (!Filesystem::pathExists($dirname)) { 69 + Filesystem::createDirectory($dirname, 0755, $recursive = true); 76 70 } 77 - } else { 78 - $this->log( 79 - "Updating the working copy for repository '%s'.", 80 - $callsign); 81 - if ($is_git) { 82 - $this->executeGitUpdate(); 71 + 72 + if (!Filesystem::pathExists($local_path)) { 73 + $this->logPull( 74 + pht( 75 + "Creating a new working copy for repository '%s'.", 76 + $callsign)); 77 + if ($is_git) { 78 + $this->executeGitCreate(); 79 + } else { 80 + $this->executeMercurialCreate(); 81 + } 83 82 } else { 84 - $this->executeMercurialUpdate(); 83 + $this->logPull( 84 + pht( 85 + "Updating the working copy for repository '%s'.", 86 + $callsign)); 87 + if ($is_git) { 88 + $this->executeGitUpdate(); 89 + } else { 90 + $this->executeMercurialUpdate(); 91 + } 85 92 } 93 + } catch (Exception $ex) { 94 + $this->abortPull( 95 + pht('Pull of "%s" failed: %s', $callsign, $ex->getMessage()), 96 + $ex); 86 97 } 98 + 99 + $this->donePull(); 87 100 88 101 return $this; 102 + } 103 + 104 + private function skipPull($message) { 105 + $this->updateRepositoryInitStatus(null); 106 + $this->log('%s', $message); 107 + } 108 + 109 + private function abortPull($message, Exception $ex = null) { 110 + $code_error = PhabricatorRepositoryStatusMessage::CODE_ERROR; 111 + $this->updateRepositoryInitStatus($code_error, $message); 112 + if ($ex) { 113 + throw $ex; 114 + } else { 115 + throw new Exception($message); 116 + } 117 + } 118 + 119 + private function logPull($message) { 120 + $code_working = PhabricatorRepositoryStatusMessage::CODE_WORKING; 121 + $this->updateRepositoryInitStatus($code_working, $message); 122 + $this->log('%s', $message); 123 + } 124 + 125 + private function donePull() { 126 + $code_okay = PhabricatorRepositoryStatusMessage::CODE_OKAY; 127 + $this->updateRepositoryInitStatus($code_okay); 128 + } 129 + 130 + private function updateRepositoryInitStatus($code, $message = null) { 131 + $this->getRepository()->writeStatusMessage( 132 + PhabricatorRepositoryStatusMessage::TYPE_INIT, 133 + $code, 134 + array( 135 + 'message' => $message 136 + )); 89 137 } 90 138 91 139
+37
src/applications/repository/storage/PhabricatorRepository.php
··· 815 815 } 816 816 } 817 817 818 + public function writeStatusMessage( 819 + $status_type, 820 + $status_code, 821 + array $parameters = array()) { 822 + 823 + $table = new PhabricatorRepositoryStatusMessage(); 824 + $conn_w = $table->establishConnection('w'); 825 + $table_name = $table->getTableName(); 826 + 827 + if ($status_code === null) { 828 + queryfx( 829 + $conn_w, 830 + 'DELETE FROM %T WHERE repositoryID = %d AND statusType = %s', 831 + $table_name, 832 + $this->getID(), 833 + $status_type); 834 + } else { 835 + queryfx( 836 + $conn_w, 837 + 'INSERT INTO %T 838 + (repositoryID, statusType, statusCode, parameters, epoch) 839 + VALUES (%d, %s, %s, %s, %d) 840 + ON DUPLICATE KEY UPDATE 841 + statusCode = VALUES(statusCode), 842 + parameters = VALUES(parameters), 843 + epoch = VALUES(epoch)', 844 + $table_name, 845 + $this->getID(), 846 + $status_type, 847 + $status_code, 848 + json_encode($parameters), 849 + time()); 850 + } 851 + 852 + return $this; 853 + } 854 + 818 855 819 856 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 820 857
+33
src/applications/repository/storage/PhabricatorRepositoryStatusMessage.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryStatusMessage 4 + extends PhabricatorRepositoryDAO { 5 + 6 + const TYPE_INIT = 'init'; 7 + const TYPE_FETCH = 'fetch'; 8 + const TYPE_NEEDS_UPDATE = 'needs-update'; 9 + 10 + const CODE_ERROR = 'error'; 11 + const CODE_WORKING = 'working'; 12 + const CODE_OKAY = 'okay'; 13 + 14 + protected $repositoryID; 15 + protected $statusType; 16 + protected $statusCode; 17 + protected $parameters = array(); 18 + protected $epoch; 19 + 20 + public function getConfiguration() { 21 + return array( 22 + self::CONFIG_TIMESTAMPS => false, 23 + self::CONFIG_SERIALIZATION => array( 24 + 'parameters' => self::SERIALIZATION_JSON, 25 + ), 26 + ) + parent::getConfiguration(); 27 + } 28 + 29 + public function getParameter($key, $default = null) { 30 + return idx($this->parameters, $key, $default); 31 + } 32 + 33 + }
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1712 1712 'type' => 'sql', 1713 1713 'name' => $this->getPatchPath('20131026.commitstatus.sql'), 1714 1714 ), 1715 + '20131030.repostatusmessage.sql' => array( 1716 + 'type' => 'sql', 1717 + 'name' => $this->getPatchPath('20131030.repostatusmessage.sql'), 1718 + ), 1715 1719 ); 1716 1720 } 1717 1721 }