1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-25 22:18:19 +01:00

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
This commit is contained in:
epriestley 2013-10-30 16:04:19 -07:00
parent edd8bea85b
commit 3a39b01233
7 changed files with 215 additions and 36 deletions

View file

@ -0,0 +1,10 @@
CREATE TABLE {$NAMESPACE}_repository.repository_statusmessage (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
repositoryID INT UNSIGNED NOT NULL,
statusType VARCHAR(32) NOT NULL COLLATE utf8_bin,
statusCode VARCHAR(32) NOT NULL COLLATE utf8_bin,
parameters LONGTEXT NOT NULL,
epoch INT UNSIGNED NOT NULL,
UNIQUE KEY (repositoryID, statusType)
) ENGINE=InnoDB, CHARSET utf8;

View file

@ -1665,6 +1665,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php', 'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php',
'PhabricatorRepositorySearchEngine' => 'applications/repository/query/PhabricatorRepositorySearchEngine.php', 'PhabricatorRepositorySearchEngine' => 'applications/repository/query/PhabricatorRepositorySearchEngine.php',
'PhabricatorRepositoryShortcut' => 'applications/repository/storage/PhabricatorRepositoryShortcut.php', 'PhabricatorRepositoryShortcut' => 'applications/repository/storage/PhabricatorRepositoryShortcut.php',
'PhabricatorRepositoryStatusMessage' => 'applications/repository/storage/PhabricatorRepositoryStatusMessage.php',
'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php',
'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositorySvnCommitMessageParserWorker.php', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositorySvnCommitMessageParserWorker.php',
'PhabricatorRepositorySymbol' => 'applications/repository/storage/PhabricatorRepositorySymbol.php', 'PhabricatorRepositorySymbol' => 'applications/repository/storage/PhabricatorRepositorySymbol.php',
@ -4005,6 +4006,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositorySearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorRepositorySearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryStatusMessage' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO',

View file

@ -565,6 +565,10 @@ final class DiffusionRepositoryEditMainController
$view = new PHUIStatusListView(); $view = new PHUIStatusListView();
$messages = id(new PhabricatorRepositoryStatusMessage())
->loadAllWhere('repositoryID = %d', $repository->getID());
$messages = mpull($messages, null, 'getStatusType');
if ($repository->isTracked()) { if ($repository->isTracked()) {
$view->addItem( $view->addItem(
id(new PHUIStatusItemView()) id(new PHUIStatusItemView())
@ -655,12 +659,53 @@ final class DiffusionRepositoryEditMainController
if ($repository->usesLocalWorkingCopy()) { if ($repository->usesLocalWorkingCopy()) {
$local_path = $repository->getLocalPath(); $local_path = $repository->getLocalPath();
if (Filesystem::pathExists($local_path)) { $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);
$view->addItem( if ($message) {
id(new PHUIStatusItemView()) switch ($message->getStatusCode()) {
->setIcon('accept-green') case PhabricatorRepositoryStatusMessage::CODE_ERROR:
->setTarget(pht('Working Copy OK')) $view->addItem(
->setNote(phutil_tag('tt', array(), $local_path))); id(new PHUIStatusItemView())
->setIcon('warning-red')
->setTarget(pht('Initialization Error'))
->setNote($message->getParameter('message')));
return $view;
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
if (Filesystem::pathExists($local_path)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(pht('Working Copy OK'))
->setNote(phutil_tag('tt', array(), $local_path)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('warning-red')
->setTarget(pht('Working Copy Error'))
->setNote(
pht(
'Working copy %s has been deleted, or is not '.
'readable by the webserver. Make this directory '.
'readable. If it has been deleted, the daemons should '.
'restore it automatically.',
phutil_tag('tt', array(), $local_path))));
return $view;
}
break;
case PhabricatorRepositoryStatusMessage::CODE_WORKING:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('time-green')
->setTarget(pht('Initializing Working Copy'))
->setNote(pht('Daemons are initilizing the working copy.')));
return $view;
default:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('warning-red')
->setTarget(pht('Unknown Init Status'))
->setNote($message->getStatusCode()));
return $view;
}
} else { } else {
$view->addItem( $view->addItem(
id(new PHUIStatusItemView()) id(new PHUIStatusItemView())

View file

@ -27,7 +27,7 @@ final class PhabricatorRepositoryPullEngine
$callsign = $repository->getCallsign(); $callsign = $repository->getCallsign();
if ($repository->isHosted()) { if ($repository->isHosted()) {
$this->log( $this->skipPull(
pht( pht(
'Repository "%s" is hosted, so Phabricator does not pull updates '. 'Repository "%s" is hosted, so Phabricator does not pull updates '.
'for it.', 'for it.',
@ -38,10 +38,11 @@ final class PhabricatorRepositoryPullEngine
switch ($vcs) { switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// We never pull a local copy of Subversion repositories. // We never pull a local copy of Subversion repositories.
$this->log( $this->skipPull(
"Repository '%s' is a Subversion repository, which does not require ". pht(
"a local working copy to be pulled.", "Repository '%s' is a Subversion repository, which does not ".
$callsign); "require a local working copy to be pulled.",
$callsign));
return; return;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true; $is_git = true;
@ -50,44 +51,91 @@ final class PhabricatorRepositoryPullEngine
$is_hg = true; $is_hg = true;
break; break;
default: default:
throw new Exception("Unsupported VCS '{$vcs}'!"); $this->abortPull(pht('Unknown VCS "%s"!', $vcs));
} }
$callsign = $repository->getCallsign(); $callsign = $repository->getCallsign();
$local_path = $repository->getLocalPath(); $local_path = $repository->getLocalPath();
if ($local_path === null) { if ($local_path === null) {
throw new Exception( $this->abortPull(
"No local path is configured for repository '{$callsign}'."); pht(
"No local path is configured for repository '%s'.",
$callsign));
} }
$dirname = dirname($local_path); try {
if (!Filesystem::pathExists($dirname)) { $dirname = dirname($local_path);
Filesystem::createDirectory($dirname, 0755, $recursive = true); if (!Filesystem::pathExists($dirname)) {
Filesystem::createDirectory($dirname, 0755, $recursive = true);
}
if (!Filesystem::pathExists($local_path)) {
$this->logPull(
pht(
"Creating a new working copy for repository '%s'.",
$callsign));
if ($is_git) {
$this->executeGitCreate();
} else {
$this->executeMercurialCreate();
}
} else {
$this->logPull(
pht(
"Updating the working copy for repository '%s'.",
$callsign));
if ($is_git) {
$this->executeGitUpdate();
} else {
$this->executeMercurialUpdate();
}
}
} catch (Exception $ex) {
$this->abortPull(
pht('Pull of "%s" failed: %s', $callsign, $ex->getMessage()),
$ex);
} }
if (!Filesystem::pathExists($local_path)) { $this->donePull();
$this->log(
"Creating a new working copy for repository '%s'.",
$callsign);
if ($is_git) {
$this->executeGitCreate();
} else {
$this->executeMercurialCreate();
}
} else {
$this->log(
"Updating the working copy for repository '%s'.",
$callsign);
if ($is_git) {
$this->executeGitUpdate();
} else {
$this->executeMercurialUpdate();
}
}
return $this; return $this;
} }
private function skipPull($message) {
$this->updateRepositoryInitStatus(null);
$this->log('%s', $message);
}
private function abortPull($message, Exception $ex = null) {
$code_error = PhabricatorRepositoryStatusMessage::CODE_ERROR;
$this->updateRepositoryInitStatus($code_error, $message);
if ($ex) {
throw $ex;
} else {
throw new Exception($message);
}
}
private function logPull($message) {
$code_working = PhabricatorRepositoryStatusMessage::CODE_WORKING;
$this->updateRepositoryInitStatus($code_working, $message);
$this->log('%s', $message);
}
private function donePull() {
$code_okay = PhabricatorRepositoryStatusMessage::CODE_OKAY;
$this->updateRepositoryInitStatus($code_okay);
}
private function updateRepositoryInitStatus($code, $message = null) {
$this->getRepository()->writeStatusMessage(
PhabricatorRepositoryStatusMessage::TYPE_INIT,
$code,
array(
'message' => $message
));
}
/* -( Pulling Git Working Copies )----------------------------------------- */ /* -( Pulling Git Working Copies )----------------------------------------- */

View file

@ -815,6 +815,43 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
} }
} }
public function writeStatusMessage(
$status_type,
$status_code,
array $parameters = array()) {
$table = new PhabricatorRepositoryStatusMessage();
$conn_w = $table->establishConnection('w');
$table_name = $table->getTableName();
if ($status_code === null) {
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d AND statusType = %s',
$table_name,
$this->getID(),
$status_type);
} else {
queryfx(
$conn_w,
'INSERT INTO %T
(repositoryID, statusType, statusCode, parameters, epoch)
VALUES (%d, %s, %s, %s, %d)
ON DUPLICATE KEY UPDATE
statusCode = VALUES(statusCode),
parameters = VALUES(parameters),
epoch = VALUES(epoch)',
$table_name,
$this->getID(),
$status_type,
$status_code,
json_encode($parameters),
time());
}
return $this;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -0,0 +1,33 @@
<?php
final class PhabricatorRepositoryStatusMessage
extends PhabricatorRepositoryDAO {
const TYPE_INIT = 'init';
const TYPE_FETCH = 'fetch';
const TYPE_NEEDS_UPDATE = 'needs-update';
const CODE_ERROR = 'error';
const CODE_WORKING = 'working';
const CODE_OKAY = 'okay';
protected $repositoryID;
protected $statusType;
protected $statusCode;
protected $parameters = array();
protected $epoch;
public function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
self::CONFIG_SERIALIZATION => array(
'parameters' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function getParameter($key, $default = null) {
return idx($this->parameters, $key, $default);
}
}

View file

@ -1712,6 +1712,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
'type' => 'sql', 'type' => 'sql',
'name' => $this->getPatchPath('20131026.commitstatus.sql'), 'name' => $this->getPatchPath('20131026.commitstatus.sql'),
), ),
'20131030.repostatusmessage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131030.repostatusmessage.sql'),
),
); );
} }
} }