Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15385346
D7705.id17429.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
18 KB
Referenced Files
None
Subscribers
None
D7705.id17429.diff
View Options
Index: resources/sql/patches/20131204.pushlog.sql
===================================================================
--- /dev/null
+++ resources/sql/patches/20131204.pushlog.sql
@@ -0,0 +1,25 @@
+CREATE TABLE {$NAMESPACE}_repository.repository_pushlog (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ epoch INT UNSIGNED NOT NULL,
+ repositoryPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ pusherPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ remoteAddress INT UNSIGNED,
+ remoteProtocol VARCHAR(32),
+ transactionKey CHAR(12) NOT NULL COLLATE latin1_bin,
+ refType VARCHAR(12) NOT NULL COLLATE utf8_bin,
+ refNameHash VARCHAR(12) COLLATE latin1_bin,
+ refNameRaw LONGTEXT COLLATE latin1_bin,
+ refNameEncoding VARCHAR(16) COLLATE utf8_bin,
+ refOld VARCHAR(40) COLLATE latin1_bin,
+ refNew VARCHAR(40) NOT NULL COLLATE latin1_bin,
+ mergeBase VARCHAR(40) COLLATE latin1_bin,
+ changeFlags INT UNSIGNED NOT NULL,
+ rejectCode INT UNSIGNED NOT NULL,
+ rejectDetails VARCHAR(64) COLLATE utf8_bin,
+
+ KEY `key_repository` (repositoryPHID),
+ KEY `key_ref` (repositoryPHID, refNew),
+ KEY `key_pusher` (pusherPHID),
+ KEY `key_name` (repositoryPHID, refNameHash)
+
+) ENGINE=InnoDB, COLLATE=utf8_general_ci;
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -522,6 +522,7 @@
'DiffusionPathQuery' => 'applications/diffusion/query/DiffusionPathQuery.php',
'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php',
'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php',
+ 'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php',
'DiffusionQuery' => 'applications/diffusion/query/DiffusionQuery.php',
'DiffusionRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionRawDiffQuery.php',
'DiffusionRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRemarkupRule.php',
@@ -1793,6 +1794,9 @@
'PhabricatorRepositoryPHIDTypeRepository' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php',
'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php',
'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php',
+ 'PhabricatorRepositoryPushLog' => 'applications/repository/storage/PhabricatorRepositoryPushLog.php',
+ 'PhabricatorRepositoryPushLogQuery' => 'applications/repository/query/PhabricatorRepositoryPushLogQuery.php',
+ 'PhabricatorRepositoryPushLogSearchEngine' => 'applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php',
'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php',
'PhabricatorRepositorySearchEngine' => 'applications/repository/query/PhabricatorRepositorySearchEngine.php',
'PhabricatorRepositoryShortcut' => 'applications/repository/storage/PhabricatorRepositoryShortcut.php',
@@ -2848,6 +2852,11 @@
'DiffusionPathCompleteController' => 'DiffusionController',
'DiffusionPathQueryTestCase' => 'PhabricatorTestCase',
'DiffusionPathValidateController' => 'DiffusionController',
+ 'DiffusionPushLogListController' =>
+ array(
+ 0 => 'DiffusionController',
+ 1 => 'PhabricatorApplicationSearchResultsControllerInterface',
+ ),
'DiffusionQuery' => 'PhabricatorQuery',
'DiffusionRawDiffQuery' => 'DiffusionQuery',
'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObject',
@@ -4309,6 +4318,13 @@
'PhabricatorRepositoryPHIDTypeRepository' => 'PhabricatorPHIDType',
'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine',
'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon',
+ 'PhabricatorRepositoryPushLog' =>
+ array(
+ 0 => 'PhabricatorRepositoryDAO',
+ 1 => 'PhabricatorPolicyInterface',
+ ),
+ 'PhabricatorRepositoryPushLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorRepositoryPushLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositorySearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO',
Index: src/applications/diffusion/application/PhabricatorApplicationDiffusion.php
===================================================================
--- src/applications/diffusion/application/PhabricatorApplicationDiffusion.php
+++ src/applications/diffusion/application/PhabricatorApplicationDiffusion.php
@@ -46,6 +46,9 @@
'new/' => 'DiffusionRepositoryNewController',
'(?P<edit>create)/' => 'DiffusionRepositoryCreateController',
'(?P<edit>import)/' => 'DiffusionRepositoryCreateController',
+ 'pushlog/(?:query/(?P<queryKey>[^/]+)/)?'
+ => 'DiffusionPushLogListController',
+
'(?P<callsign>[A-Z]+)/' => array(
'' => 'DiffusionRepositoryController',
@@ -58,7 +61,6 @@
'tags/(?P<dblob>.*)' => 'DiffusionTagListController',
'branches/(?P<dblob>.*)' => 'DiffusionBranchTableController',
'lint/(?P<dblob>.*)' => 'DiffusionLintController',
-
'commit/(?P<commit>[a-z0-9]+)/branches/'
=> 'DiffusionCommitBranchesController',
'commit/(?P<commit>[a-z0-9]+)/tags/'
Index: src/applications/diffusion/controller/DiffusionPushLogListController.php
===================================================================
--- /dev/null
+++ src/applications/diffusion/controller/DiffusionPushLogListController.php
@@ -0,0 +1,96 @@
+<?php
+
+final class DiffusionPushLogListController extends DiffusionController
+ implements PhabricatorApplicationSearchResultsControllerInterface {
+
+ private $queryKey;
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function willProcessRequest(array $data) {
+ $this->queryKey = idx($data, 'queryKey');
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $controller = id(new PhabricatorApplicationSearchController($request))
+ ->setQueryKey($this->queryKey)
+ ->setSearchEngine(new PhabricatorRepositoryPushLogSearchEngine())
+ ->setNavigation($this->buildSideNavView());
+
+ return $this->delegateToController($controller);
+ }
+
+ public function renderResultsList(
+ array $logs,
+ PhabricatorSavedQuery $query) {
+ $viewer = $this->getRequest()->getUser();
+
+ $this->loadHandles(mpull($logs, 'getPusherPHID'));
+
+ $rows = array();
+ foreach ($logs as $log) {
+ $callsign = $log->getRepository()->getCallsign();
+ $rows[] = array(
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => $this->getApplicationURI($callsign.'/'),
+ ),
+ $callsign),
+ $this->getHandle($log->getPusherPHID())->renderLink(),
+ $log->getRefType(),
+ $log->getRefName(),
+ $log->getRefOldShort(),
+ $log->getRefNewShort(),
+ phabricator_datetime($log->getEpoch(), $viewer),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setHeaders(
+ array(
+ pht('Repository'),
+ pht('Pusher'),
+ pht('Type'),
+ pht('Name'),
+ pht('Old'),
+ pht('New'),
+ pht('Date'),
+ ))
+ ->setColumnClasses(
+ array(
+ '',
+ '',
+ '',
+ 'wide',
+ 'n',
+ 'n',
+ 'date',
+ ));
+
+ $box = id(new PHUIBoxView())
+ ->addMargin(PHUI::MARGIN_LARGE)
+ ->appendChild($table);
+
+ return $box;
+ }
+
+ public function buildSideNavView($for_app = false) {
+ $viewer = $this->getRequest()->getUser();
+
+ $nav = new AphrontSideNavFilterView();
+ $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
+
+ id(new PhabricatorRepositoryPushLogSearchEngine())
+ ->setViewer($viewer)
+ ->addNavigationItems($nav->getMenu());
+
+ $nav->selectFilter(null);
+
+ return $nav;
+ }
+
+}
Index: src/applications/diffusion/engine/DiffusionCommitHookEngine.php
===================================================================
--- src/applications/diffusion/engine/DiffusionCommitHookEngine.php
+++ src/applications/diffusion/engine/DiffusionCommitHookEngine.php
@@ -1,5 +1,10 @@
<?php
+/**
+ * @task git Git Hooks
+ * @task hg Mercurial Hooks
+ * @task svn Subversion Hooks
+ */
final class DiffusionCommitHookEngine extends Phobject {
private $viewer;
@@ -77,6 +82,48 @@
// TODO: Now, do content checks.
+ // TODO: Generalize this; just getting some data in the database for now.
+ $transaction_key = PhabricatorHash::digestForIndex(
+ Filesystem::readRandomBytes(64));
+
+ $logs = array();
+ foreach ($updates as $update) {
+ $log = PhabricatorRepositoryPushLog::initializeNewLog($this->getViewer())
+ ->setRepositoryPHID($this->getRepository()->getPHID())
+ ->setEpoch(time())
+ ->setRemoteAddress(null) // TODO: Populate this where possible.
+ ->setRemoteProtocol(null) // TODO: Populate this where possible.
+ ->setTransactionKey($transaction_key)
+ ->setRefType($update['type'])
+ ->setRefNameHash(PhabricatorHash::digestForIndex($update['ref']))
+ ->setRefNameRaw($update['ref'])
+ ->setRefNameEncoding(phutil_is_utf8($update['ref']) ? 'utf8' : null)
+ ->setRefOld($update['old'])
+ ->setRefNew($update['new'])
+ ->setMergeBase(idx($update, 'merge-base'))
+ ->setRejectCode(PhabricatorRepositoryPushLog::REJECT_ACCEPT)
+ ->setRejectDetails(null);
+
+ $flags = 0;
+ if ($update['operation'] == 'create') {
+ $flags = $flags | PhabricatorRepositoryPushLog::CHANGEFLAG_ADD;
+ } else if ($update['operation'] == 'delete') {
+ $flags = $flags | PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE;
+ } else {
+ // TODO: This isn't correct; these might be APPEND or REWRITE, and
+ // if they're REWRITE they might be DANGEROUS. Fix this when this
+ // gets generalized.
+ $flags = $flags | PhabricatorRepositoryPushLog::CHANGEFLAG_APPEND;
+ }
+
+ $log->setChangeFlags($flags);
+ $logs[] = $log;
+ }
+
+ foreach ($logs as $log) {
+ $log->save();
+ }
+
return 0;
}
Index: src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php
===================================================================
--- /dev/null
+++ src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php
@@ -0,0 +1,86 @@
+<?php
+
+final class PhabricatorRepositoryPushLogQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $repositoryPHIDs;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withRepositoryPHIDs(array $repository_phids) {
+ $this->repositoryPHIDs = $repository_phids;
+ return $this;
+ }
+
+ protected function loadPage() {
+ $table = new PhabricatorRepositoryPushLog();
+ $conn_r = $table->establishConnection('r');
+
+ $data = queryfx_all(
+ $conn_r,
+ 'SELECT * FROM %T %Q %Q %Q',
+ $table->getTableName(),
+ $this->buildWhereClause($conn_r),
+ $this->buildOrderClause($conn_r),
+ $this->buildLimitClause($conn_r));
+
+ return $table->loadAllFromArray($data);
+ }
+
+ public function willFilterPage(array $logs) {
+ $repository_phids = mpull($logs, 'getRepositoryPHID');
+ if ($repository_phids) {
+ $repositories = id(new PhabricatorRepositoryQuery())
+ ->setViewer($this->getViewer())
+ ->withPHIDs($repository_phids)
+ ->execute();
+ $repositories = mpull($repositories, null, 'getPHID');
+ } else {
+ $repositories = array();
+ }
+
+ foreach ($logs as $key => $log) {
+ $phid = $log->getRepositoryPHID();
+ if (empty($repositories[$phid])) {
+ unset($logs[$key]);
+ continue;
+ }
+ $log->attachRepository($repositories[$phid]);
+ }
+
+ return $logs;
+ }
+
+
+ private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
+ $where = array();
+
+ if ($this->ids) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->repositoryPHIDs) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'repositoryPHID IN (%Ls)',
+ $this->repositoryPHIDs);
+ }
+
+ $where[] = $this->buildPagingClause($conn_r);
+
+ return $this->formatWhereClause($where);
+ }
+
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorApplicationDiffusion';
+ }
+
+}
Index: src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php
===================================================================
--- /dev/null
+++ src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php
@@ -0,0 +1,49 @@
+<?php
+
+final class PhabricatorRepositoryPushLogSearchEngine
+ extends PhabricatorApplicationSearchEngine {
+
+ public function buildSavedQueryFromRequest(AphrontRequest $request) {
+ $saved = new PhabricatorSavedQuery();
+
+ return $saved;
+ }
+
+ public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
+ $query = id(new PhabricatorRepositoryPushLogQuery());
+
+ return $query;
+ }
+
+ public function buildSearchForm(
+ AphrontFormView $form,
+ PhabricatorSavedQuery $saved_query) {
+
+ }
+
+ protected function getURI($path) {
+ return '/diffusion/pushlog/'.$path;
+ }
+
+ public function getBuiltinQueryNames() {
+ $names = array(
+ 'all' => pht('All Push Logs'),
+ );
+
+ return $names;
+ }
+
+ public function buildSavedQueryFromBuiltin($query_key) {
+
+ $query = $this->newSavedQuery();
+ $query->setQueryKey($query_key);
+
+ switch ($query_key) {
+ case 'all':
+ return $query;
+ }
+
+ return parent::buildSavedQueryFromBuiltin($query_key);
+ }
+
+}
Index: src/applications/repository/storage/PhabricatorRepositoryPushLog.php
===================================================================
--- /dev/null
+++ src/applications/repository/storage/PhabricatorRepositoryPushLog.php
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Records a push to a hosted repository. This allows us to store metadata
+ * about who pushed commits, when, and from where. We can also record the
+ * history of branches and tags, which is not normally persisted outside of
+ * the reflog.
+ *
+ * This log is written by commit hooks installed into hosted repositories.
+ * See @{class:DiffusionCommitHookEngine}.
+ */
+final class PhabricatorRepositoryPushLog
+ extends PhabricatorRepositoryDAO
+ implements PhabricatorPolicyInterface {
+
+ const REFTYPE_BRANCH = 'branch';
+ const REFTYPE_TAG = 'tag';
+ const REFTYPE_BOOKMARK = 'bookmark';
+ const REFTYPE_SVN = 'svn';
+ const REFTYPE_COMMIT = 'commit';
+
+ const CHANGEFLAG_ADD = 1;
+ const CHANGEFLAG_DELETE = 2;
+ const CHANGEFLAG_APPEND = 4;
+ const CHANGEFLAG_REWRITE = 8;
+ const CHANGEFLAG_DANGEROUS = 16;
+
+ const REJECT_ACCEPT = 0;
+ const REJECT_DANGEROUS = 1;
+ const REJECT_HERALD = 2;
+ const REJECT_EXTERNAL = 3;
+
+ protected $repositoryPHID;
+ protected $epoch;
+ protected $pusherPHID;
+ protected $remoteAddress;
+ protected $remoteProtocol;
+ protected $transactionKey;
+ protected $refType;
+ protected $refNameHash;
+ protected $refNameRaw;
+ protected $refNameEncoding;
+ protected $refOld;
+ protected $refNew;
+ protected $mergeBase;
+ protected $changeFlags;
+ protected $rejectCode;
+ protected $rejectDetails;
+
+ private $repository = self::ATTACHABLE;
+
+ public static function initializeNewLog(PhabricatorUser $viewer) {
+ return id(new PhabricatorRepositoryPushLog())
+ ->setPusherPHID($viewer->getPHID());
+ }
+
+ public function getConfiguration() {
+ return array(
+ self::CONFIG_TIMESTAMPS => false,
+ ) + parent::getConfiguration();
+ }
+
+ public function attachRepository(PhabricatorRepository $repository) {
+ $this->repository = $repository;
+ return $this;
+ }
+
+ public function getRepository() {
+ return $this->assertAttached($this->repository);
+ }
+
+ public function getRefName() {
+ if ($this->getRefNameEncoding() == 'utf8') {
+ return $this->getRefNameRaw();
+ }
+ return phutil_utf8ize($this->getRefNameRaw());
+ }
+
+ public function getRefOldShort() {
+ if ($this->getRepository()->isSVN()) {
+ return $this->getRefOld();
+ }
+ return substr($this->getRefOld(), 0, 12);
+ }
+
+ public function getRefNewShort() {
+ if ($this->getRepository()->isSVN()) {
+ return $this->getRefNew();
+ }
+ return substr($this->getRefNew(), 0, 12);
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ );
+ }
+
+ public function getPolicy($capability) {
+ return $this->getRepository()->getPolicy($capability);
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return pht(
+ "A repository's push logs are visible to users who can see the ".
+ "repository.");
+ }
+
+}
Index: src/docs/user/userguide/diffusion_hosting.diviner
===================================================================
--- src/docs/user/userguide/diffusion_hosting.diviner
+++ src/docs/user/userguide/diffusion_hosting.diviner
@@ -31,8 +31,10 @@
| Reads | Yes | Yes |
| Writes | Yes | Yes |
| Authenticated Access | Yes | Yes |
+| Push Logs | Yes | Yes |
+| Commit Hooks | Yes | Yes |
| Anonymous Access | No | Yes |
-| Security | Better (Asymetric Key) | Okay (Password) |
+| Security | Better (Asymmetric Key) | Okay (Password) |
| Performance | Better | Okay |
| Setup | Hard | Easy |
Index: src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
===================================================================
--- src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1800,6 +1800,10 @@
'type' => 'sql',
'name' => $this->getPatchPath('20131205.buildtargets.sql'),
),
+ '20131204.pushlog.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131204.pushlog.sql'),
+ ),
);
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 15, 10:20 PM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7308982
Default Alt Text
D7705.id17429.diff (18 KB)
Attached To
Mode
D7705: Add a basic push log for recording repository push events
Attached
Detach File
Event Timeline
Log In to Comment