Page MenuHomePhabricator

D19443.id46541.diff
No OneTemporary

D19443.id46541.diff

diff --git a/resources/sql/autopatches/20180509.repo_identity.commits.sql b/resources/sql/autopatches/20180509.repo_identity.commits.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20180509.repo_identity.commits.sql
@@ -0,0 +1,3 @@
+ALTER TABLE {$NAMESPACE}_repository.repository_commit
+ ADD COLUMN authorIdentityPHID VARBINARY(64) DEFAULT NULL,
+ ADD COLUMN committerIdentityPHID VARBINARY(64) DEFAULT NULL;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -815,8 +815,12 @@
'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php',
'DiffusionHistoryView' => 'applications/diffusion/view/DiffusionHistoryView.php',
'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php',
+ 'DiffusionIdentityAssigneeDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php',
+ 'DiffusionIdentityAssigneeEditField' => 'applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php',
+ 'DiffusionIdentityAssigneeSearchField' => 'applications/diffusion/searchfield/DiffusionIdentityAssigneeSearchField.php',
'DiffusionIdentityEditController' => 'applications/diffusion/controller/DiffusionIdentityEditController.php',
'DiffusionIdentityListController' => 'applications/diffusion/controller/DiffusionIdentityListController.php',
+ 'DiffusionIdentityUnassignedDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityUnassignedDatasource.php',
'DiffusionIdentityViewController' => 'applications/diffusion/controller/DiffusionIdentityViewController.php',
'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php',
'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php',
@@ -4092,6 +4096,7 @@
'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php',
'PhabricatorRepositoryIdentity' => 'applications/repository/storage/PhabricatorRepositoryIdentity.php',
'PhabricatorRepositoryIdentityAssignTransaction' => 'applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php',
+ 'PhabricatorRepositoryIdentityChangeWorker' => 'applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php',
'PhabricatorRepositoryIdentityEditEngine' => 'applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php',
'PhabricatorRepositoryIdentityFerretEngine' => 'applications/repository/search/PhabricatorRepositoryIdentityFerretEngine.php',
'PhabricatorRepositoryIdentityPHIDType' => 'applications/repository/phid/PhabricatorRepositoryIdentityPHIDType.php',
@@ -6166,8 +6171,12 @@
'DiffusionHistoryTableView' => 'DiffusionHistoryView',
'DiffusionHistoryView' => 'DiffusionView',
'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
+ 'DiffusionIdentityAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'DiffusionIdentityAssigneeEditField' => 'PhabricatorTokenizerEditField',
+ 'DiffusionIdentityAssigneeSearchField' => 'PhabricatorSearchTokenizerField',
'DiffusionIdentityEditController' => 'DiffusionController',
'DiffusionIdentityListController' => 'DiffusionController',
+ 'DiffusionIdentityUnassignedDatasource' => 'PhabricatorTypeaheadDatasource',
'DiffusionIdentityViewController' => 'DiffusionController',
'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController',
'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController',
@@ -10000,6 +10009,7 @@
'PhabricatorApplicationTransactionInterface',
),
'PhabricatorRepositoryIdentityAssignTransaction' => 'PhabricatorRepositoryIdentityTransactionType',
+ 'PhabricatorRepositoryIdentityChangeWorker' => 'PhabricatorWorker',
'PhabricatorRepositoryIdentityEditEngine' => 'PhabricatorEditEngine',
'PhabricatorRepositoryIdentityFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorRepositoryIdentityPHIDType' => 'PhabricatorPHIDType',
diff --git a/src/applications/diffusion/controller/DiffusionIdentityViewController.php b/src/applications/diffusion/controller/DiffusionIdentityViewController.php
--- a/src/applications/diffusion/controller/DiffusionIdentityViewController.php
+++ b/src/applications/diffusion/controller/DiffusionIdentityViewController.php
@@ -104,13 +104,13 @@
}
$properties->addProperty(
pht('Effective User'),
- $viewer->renderHandle($effective_phid));
+ $this->buildPropertyValue($effective_phid));
$properties->addProperty(
pht('Automatically Detected User'),
- $viewer->renderHandle($automatic_phid));
+ $this->buildPropertyValue($automatic_phid));
$properties->addProperty(
pht('Manually Set User'),
- $viewer->renderHandle($manual_phid));
+ $this->buildPropertyValue($manual_phid));
$header = id(new PHUIHeaderView())
->setHeader(array(pht('Identity Assignments'), $tag));
@@ -120,4 +120,16 @@
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
}
+
+ private function buildPropertyValue($value) {
+ $viewer = $this->getViewer();
+
+ if ($value == DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN) {
+ return phutil_tag('em', array(), pht('Explicitly Unassigned'));
+ } else if (!$value) {
+ return null;
+ } else {
+ return $viewer->renderHandle($value);
+ }
+ }
}
diff --git a/src/applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php b/src/applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php
@@ -0,0 +1,22 @@
+<?php
+
+final class DiffusionIdentityAssigneeEditField
+ extends PhabricatorTokenizerEditField {
+
+ protected function newDatasource() {
+ return new DiffusionIdentityAssigneeDatasource();
+ }
+
+ protected function newHTTPParameterType() {
+ return new AphrontUserListHTTPParameterType();
+ }
+
+ protected function newConduitParameterType() {
+ if ($this->getIsSingleValue()) {
+ return new ConduitUserParameterType();
+ } else {
+ return new ConduitUserListParameterType();
+ }
+ }
+
+}
diff --git a/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php b/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php
--- a/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php
+++ b/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php
@@ -17,6 +17,14 @@
protected function buildCustomSearchFields() {
return array(
+ id(new DiffusionIdentityAssigneeSearchField())
+ ->setLabel(pht('Assigned To'))
+ ->setKey('assignee')
+ ->setDescription(pht('Search for identities by assignee.')),
+ id(new PhabricatorSearchTextField())
+ ->setLabel(pht('Identity Contains'))
+ ->setKey('match')
+ ->setDescription(pht('Search for identities by substring.')),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Is Assigned'))
->setKey('hasEffectivePHID')
@@ -34,6 +42,14 @@
$query->withHasEffectivePHID($map['hasEffectivePHID']);
}
+ if ($map['match'] !== null) {
+ $query->withIdentityNameLike($map['match']);
+ }
+
+ if ($map['assignee']) {
+ $query->withAssigneePHIDs($map['assignee']);
+ }
+
return $query;
}
diff --git a/src/applications/diffusion/searchfield/DiffusionIdentityAssigneeSearchField.php b/src/applications/diffusion/searchfield/DiffusionIdentityAssigneeSearchField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/searchfield/DiffusionIdentityAssigneeSearchField.php
@@ -0,0 +1,22 @@
+<?php
+
+final class DiffusionIdentityAssigneeSearchField
+ extends PhabricatorSearchTokenizerField {
+
+ protected function getDefaultValue() {
+ return array();
+ }
+
+ protected function getValueFromRequest(AphrontRequest $request, $key) {
+ return $this->getUsersFromRequest($request, $key);
+ }
+
+ protected function newDatasource() {
+ return new DiffusionIdentityAssigneeDatasource();
+ }
+
+ protected function newConduitParameterType() {
+ return new ConduitUserListParameterType();
+ }
+
+}
diff --git a/src/applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php b/src/applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DiffusionIdentityAssigneeDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getBrowseTitle() {
+ return pht('Browse Assignee');
+ }
+
+ public function getPlaceholderText() {
+ return pht('Type a username or function...');
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorPeopleDatasource(),
+ new DiffusionIdentityUnassignedDatasource(),
+ );
+ }
+
+}
diff --git a/src/applications/diffusion/typeahead/DiffusionIdentityUnassignedDatasource.php b/src/applications/diffusion/typeahead/DiffusionIdentityUnassignedDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/typeahead/DiffusionIdentityUnassignedDatasource.php
@@ -0,0 +1,77 @@
+<?php
+
+final class DiffusionIdentityUnassignedDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ const FUNCTION_TOKEN = 'unassigned()';
+
+ public function getBrowseTitle() {
+ return pht('Browse Explicitly Unassigned');
+ }
+
+ public function getPlaceholderText() {
+ return pht('Type "unassigned"...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorDiffusionApplication';
+ }
+
+ public function getDatasourceFunctions() {
+ return array(
+ 'unassigned' => array(
+ 'name' => pht('Explicitly Unassigned'),
+ 'summary' => pht('Find results which are not assigned.'),
+ 'description' => pht(
+ "This function includes results which have been explicitly ".
+ "unassigned. Use a query like this to find explicitly ".
+ "unassigned results:\n\n%s\n\n".
+ "If you combine this function with other functions, the query will ".
+ "return results which match the other selectors //or// have no ".
+ "assignee. For example, this query will find results which are ".
+ "assigned to `alincoln`, and will also find results which have been ".
+ "unassigned:\n\n%s",
+ '> unassigned()',
+ '> alincoln, unassigned()'),
+ ),
+ );
+ }
+
+ public function loadResults() {
+ $results = array(
+ $this->buildUnassignedResult(),
+ );
+ return $this->filterResultsAgainstTokens($results);
+ }
+
+ protected function evaluateFunction($function, array $argv_list) {
+ $results = array();
+
+ foreach ($argv_list as $argv) {
+ $results[] = self::FUNCTION_TOKEN;
+ }
+
+ return $results;
+ }
+
+ public function renderFunctionTokens($function, array $argv_list) {
+ $results = array();
+ foreach ($argv_list as $argv) {
+ $results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
+ $this->buildUnassignedResult());
+ }
+ return $results;
+ }
+
+ private function buildUnassignedResult() {
+ $name = pht('Unassigned');
+ return $this->newFunctionResult()
+ ->setName($name.' unassigned')
+ ->setDisplayName($name)
+ ->setIcon('fa-ban')
+ ->setPHID('unassigned()')
+ ->setUnique(true)
+ ->addAttribute(pht('Select results with no owner.'));
+ }
+
+}
diff --git a/src/applications/people/editor/PhabricatorUserEditor.php b/src/applications/people/editor/PhabricatorUserEditor.php
--- a/src/applications/people/editor/PhabricatorUserEditor.php
+++ b/src/applications/people/editor/PhabricatorUserEditor.php
@@ -420,6 +420,12 @@
$user->endWriteLocking();
$user->saveTransaction();
+ // Try and match this new address against unclaimed `RepositoryIdentity`s
+ PhabricatorWorker::scheduleTask(
+ 'PhabricatorRepositoryIdentityChangeWorker',
+ array('userPHID' => $user->getPHID()),
+ array('objectPHID' => $user->getPHID()));
+
return $this;
}
diff --git a/src/applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php b/src/applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php
--- a/src/applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php
+++ b/src/applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php
@@ -75,7 +75,7 @@
protected function buildCustomEditFields($object) {
return array(
- id(new PhabricatorUsersEditField())
+ id(new DiffusionIdentityAssigneeEditField())
->setKey('manuallySetUserPHID')
->setLabel(pht('Assigned To'))
->setDescription(pht('Override this identity\'s assignment.'))
diff --git a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
--- a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
+++ b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
@@ -6,6 +6,9 @@
private $ids;
private $phids;
private $identityNames;
+ private $emailAddress;
+ private $assigneePHIDs;
+ private $identityNameLike;
private $hasEffectivePHID;
public function withIDs(array $ids) {
@@ -23,6 +26,21 @@
return $this;
}
+ public function withIdentityNameLike($name_like) {
+ $this->identityNameLike = $name_like;
+ return $this;
+ }
+
+ public function withEmailAddress($address) {
+ $this->emailAddress = $address;
+ return $this;
+ }
+
+ public function withAssigneePHIDs(array $assignees) {
+ $this->assigneePHIDs = $assignees;
+ return $this;
+ }
+
public function withHasEffectivePHID($has_effective_phid) {
$this->hasEffectivePHID = $has_effective_phid;
return $this;
@@ -57,8 +75,14 @@
$this->phids);
}
- if ($this->hasEffectivePHID !== null) {
+ if ($this->assigneePHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'repository_identity.currentEffectiveUserPHID IN (%Ls)',
+ $this->assigneePHIDs);
+ }
+ if ($this->hasEffectivePHID !== null) {
if ($this->hasEffectivePHID) {
$where[] = qsprintf(
$conn,
@@ -82,6 +106,21 @@
$name_hashes);
}
+ if ($this->emailAddress !== null) {
+ $identity_style = "<{$this->emailAddress}>";
+ $where[] = qsprintf(
+ $conn,
+ 'repository_identity.identityNameRaw LIKE %<',
+ $identity_style);
+ }
+
+ if ($this->identityNameLike != null) {
+ $where[] = qsprintf(
+ $conn,
+ 'repository_identity.identityNameRaw LIKE %~',
+ $this->identityNameLike);
+ }
+
return $where;
}
diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php
--- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php
@@ -21,6 +21,8 @@
protected $repositoryID;
protected $phid;
+ protected $authorIdentityPHID;
+ protected $committerIdentityPHID;
protected $commitIdentifier;
protected $epoch;
protected $mailKey;
@@ -113,6 +115,8 @@
'commitIdentifier' => 'text40',
'mailKey' => 'bytes20',
'authorPHID' => 'phid?',
+ 'authorIdentityPHID' => 'phid?',
+ 'committerIdentityPHID' => 'phid?',
'auditStatus' => 'uint32',
'summary' => 'text255',
'importStatus' => 'uint32',
diff --git a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
--- a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
@@ -80,6 +80,7 @@
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
);
}
diff --git a/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php b/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php
new file mode 100644
--- /dev/null
+++ b/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php
@@ -0,0 +1,34 @@
+<?php
+
+final class PhabricatorRepositoryIdentityChangeWorker
+extends PhabricatorWorker {
+
+ protected function doWork() {
+ $viewer = PhabricatorUser::getOmnipotentUser();
+
+ $task_data = $this->getTaskData();
+ $user_phid = idx($task_data, 'userPHID');
+
+ $user = id(new PhabricatorPeopleQuery())
+ ->withPHIDs(array($user_phid))
+ ->setViewer($viewer)
+ ->executeOne();
+
+ $emails = id(new PhabricatorUserEmail())->loadAllWhere(
+ 'userPHID = %s ORDER BY address',
+ $user->getPHID());
+
+ foreach ($emails as $email) {
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withEmailAddress($email->getAddress())
+ ->execute();
+
+ foreach ($identities as $identity) {
+ $identity->setAutomaticGuessedUserPHID($user->getPHID())
+ ->save();
+ }
+ }
+ }
+
+}
diff --git a/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php b/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
--- a/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
+++ b/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
@@ -109,6 +109,8 @@
$data->setCommitDetail('authorName', $ref->getAuthorName());
$data->setCommitDetail('authorEmail', $ref->getAuthorEmail());
+ $data->setCommitDetail(
+ 'authorIdentityPHID', $author_identity->getPHID());
$data->setCommitDetail(
'authorPHID',
$this->resolveUserPHID($commit, $author));
@@ -124,6 +126,8 @@
$data->setCommitDetail(
'committerPHID',
$this->resolveUserPHID($commit, $committer));
+ $data->setCommitDetail(
+ 'committerIdentityPHID', $committer_identity->getPHID());
}
$repository = $this->repository;
@@ -161,6 +165,9 @@
$commit->setAuthorPHID($author_phid);
}
+ $commit->setAuthorIdentityPHID($author_identity->getPHID());
+ $commit->setCommitterIdentityPHID($committer_identity->getPHID());
+
$commit->setSummary($data->getSummary());
$commit->save();
diff --git a/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php b/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php
--- a/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php
+++ b/src/applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php
@@ -21,23 +21,33 @@
return pht(
'%s assigned this identity to %s.',
$this->renderAuthor(),
- $this->renderHandle($new));
+ $this->renderIdentityHandle($new));
} else if (!$new) {
return pht(
'%s removed %s as the assignee of this identity.',
$this->renderAuthor(),
- $this->renderHandle($old));
+ $this->renderIdentityHandle($old));
} else {
return pht(
'%s changed the assigned user for this identity from %s to %s.',
$this->renderAuthor(),
- $this->renderHandle($old),
- $this->renderHandle($new));
+ $this->renderIdentityHandle($old),
+ $this->renderIdentityHandle($new));
+ }
+ }
+
+ private function renderIdentityHandle($handle) {
+ $unassigned_token = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
+ if ($handle === $unassigned_token) {
+ return phutil_tag('em', array(), pht('Explicitly Unassigned'));
+ } else {
+ return $this->renderHandle($handle);
}
}
public function validateTransactions($object, array $xactions) {
$errors = array();
+ $unassigned_token = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
foreach ($xactions as $xaction) {
$old = $xaction->getOldValue();
@@ -50,6 +60,10 @@
continue;
}
+ if ($new === $unassigned_token) {
+ continue;
+ }
+
$assignee_list = id(new PhabricatorPeopleQuery())
->setViewer($this->getActor())
->withPHIDs(array($new))

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 22, 12:58 AM (12 h, 26 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7224600
Default Alt Text
D19443.id46541.diff (20 KB)

Event Timeline