mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-09 16:32:39 +01:00
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
This commit is contained in:
parent
2201c65eb7
commit
8a4fbcd8c0
5 changed files with 306 additions and 0 deletions
8
resources/sql/autopatches/20160824.repohint.01.hint.sql
Normal file
8
resources/sql/autopatches/20160824.repohint.01.hint.sql
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_repository.repository_commithint (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
repositoryPHID VARBINARY(64) NOT NULL,
|
||||||
|
oldCommitIdentifier VARCHAR(40) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
newCommitIdentifier VARCHAR(40) COLLATE {$COLLATE_TEXT},
|
||||||
|
hintType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
UNIQUE KEY `key_old` (repositoryPHID, oldCommitIdentifier)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -612,6 +612,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionCommitHash' => 'applications/diffusion/data/DiffusionCommitHash.php',
|
'DiffusionCommitHash' => 'applications/diffusion/data/DiffusionCommitHash.php',
|
||||||
'DiffusionCommitHeraldField' => 'applications/diffusion/herald/DiffusionCommitHeraldField.php',
|
'DiffusionCommitHeraldField' => 'applications/diffusion/herald/DiffusionCommitHeraldField.php',
|
||||||
'DiffusionCommitHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionCommitHeraldFieldGroup.php',
|
'DiffusionCommitHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionCommitHeraldFieldGroup.php',
|
||||||
|
'DiffusionCommitHintQuery' => 'applications/diffusion/query/DiffusionCommitHintQuery.php',
|
||||||
'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php',
|
'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php',
|
||||||
'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php',
|
'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php',
|
||||||
'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php',
|
'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php',
|
||||||
|
@ -3383,6 +3384,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php',
|
'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php',
|
||||||
'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php',
|
'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php',
|
||||||
'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php',
|
'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php',
|
||||||
|
'PhabricatorRepositoryCommitHint' => 'applications/repository/storage/PhabricatorRepositoryCommitHint.php',
|
||||||
'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php',
|
'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php',
|
||||||
'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php',
|
'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php',
|
||||||
'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php',
|
'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php',
|
||||||
|
@ -3403,6 +3405,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
|
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php',
|
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
|
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
|
||||||
|
'PhabricatorRepositoryManagementHintWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementHintWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
|
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php',
|
'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
|
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
|
||||||
|
@ -5104,6 +5107,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionCommitHash' => 'Phobject',
|
'DiffusionCommitHash' => 'Phobject',
|
||||||
'DiffusionCommitHeraldField' => 'HeraldField',
|
'DiffusionCommitHeraldField' => 'HeraldField',
|
||||||
'DiffusionCommitHeraldFieldGroup' => 'HeraldFieldGroup',
|
'DiffusionCommitHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||||
|
'DiffusionCommitHintQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'DiffusionCommitHookEngine' => 'Phobject',
|
'DiffusionCommitHookEngine' => 'Phobject',
|
||||||
'DiffusionCommitHookRejectException' => 'Exception',
|
'DiffusionCommitHookRejectException' => 'Exception',
|
||||||
'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField',
|
'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField',
|
||||||
|
@ -8348,6 +8352,10 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
||||||
'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
|
'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
|
||||||
'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
||||||
|
'PhabricatorRepositoryCommitHint' => array(
|
||||||
|
'PhabricatorRepositoryDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
),
|
||||||
'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
||||||
'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker',
|
||||||
'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
@ -8372,6 +8380,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
|
'PhabricatorRepositoryManagementHintWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DiffusionCommitHintQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $repositoryPHIDs;
|
||||||
|
private $oldCommitIdentifiers;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withRepositoryPHIDs(array $phids) {
|
||||||
|
$this->repositoryPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withOldCommitIdentifiers(array $identifiers) {
|
||||||
|
$this->oldCommitIdentifiers = $identifiers;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorRepositoryCommitHint();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
|
if ($this->ids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->repositoryPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'reositoryPHID IN (%Ls)',
|
||||||
|
$this->repositoryPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->oldCommitIdentifiers !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'oldCommitIdentifier IN (%Ls)',
|
||||||
|
$this->oldCommitIdentifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorDiffusionApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRepositoryManagementHintWorkflow
|
||||||
|
extends PhabricatorRepositoryManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('hint')
|
||||||
|
->setExamples('**hint** [options] ...')
|
||||||
|
->setSynopsis(
|
||||||
|
pht(
|
||||||
|
'Write hints about unusual (rewritten or unreadable) commits.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht('Reading list of hints from stdin...'));
|
||||||
|
|
||||||
|
$hints = file_get_contents('php://stdin');
|
||||||
|
if ($hints === false) {
|
||||||
|
throw new PhutilArgumentUsageException(pht('Failed to read stdin.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hints = phutil_json_decode($hints);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Expected a list of hints in JSON format: %s',
|
||||||
|
$ex->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$repositories = array();
|
||||||
|
foreach ($hints as $idx => $hint) {
|
||||||
|
if (!is_array($hint)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Each item in the list of hints should be a JSON object, but '.
|
||||||
|
'the item at index "%s" is not.',
|
||||||
|
$idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$hint,
|
||||||
|
array(
|
||||||
|
'repository' => 'string|int',
|
||||||
|
'old' => 'string',
|
||||||
|
'new' => 'optional string|null',
|
||||||
|
'hint' => 'string',
|
||||||
|
));
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Unexpected hint format at index "%s": %s',
|
||||||
|
$idx,
|
||||||
|
$ex->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_identifier = $hint['repository'];
|
||||||
|
$repository = idx($repositories, $repository_identifier);
|
||||||
|
if (!$repository) {
|
||||||
|
$repository = id(new PhabricatorRepositoryQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIdentifiers(array($repository_identifier))
|
||||||
|
->executeOne();
|
||||||
|
if (!$repository) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Repository identifier "%s" (in hint at index "%s") does not '.
|
||||||
|
'identify a valid repository.',
|
||||||
|
$repository_identifier,
|
||||||
|
$idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
$repositories[$repository_identifier] = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhabricatorRepositoryCommitHint::updateHint(
|
||||||
|
$repository->getPHID(),
|
||||||
|
$hint['old'],
|
||||||
|
idx($hint, 'new'),
|
||||||
|
$hint['hint']);
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Updated hint for "%s".',
|
||||||
|
$hint['old']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRepositoryCommitHint
|
||||||
|
extends PhabricatorRepositoryDAO
|
||||||
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
|
protected $repositoryPHID;
|
||||||
|
protected $oldCommitIdentifier;
|
||||||
|
protected $newCommitIdentifier;
|
||||||
|
protected $hintType;
|
||||||
|
|
||||||
|
const HINT_NONE = 'none';
|
||||||
|
const HINT_REWRITTEN = 'rewritten';
|
||||||
|
const HINT_UNREADABLE = 'unreadable';
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_TIMESTAMPS => false,
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'oldCommitIdentifier' => 'text40',
|
||||||
|
'newCommitIdentifier' => 'text40?',
|
||||||
|
'hintType' => 'text32',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_old' => array(
|
||||||
|
'columns' => array('repositoryPHID', 'oldCommitIdentifier'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllHintTypes() {
|
||||||
|
return array(
|
||||||
|
self::HINT_NONE,
|
||||||
|
self::HINT_REWRITTEN,
|
||||||
|
self::HINT_UNREADABLE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateHint($repository_phid, $old, $new, $type) {
|
||||||
|
switch ($type) {
|
||||||
|
case self::HINT_NONE:
|
||||||
|
break;
|
||||||
|
case self::HINT_REWRITTEN:
|
||||||
|
if (!$new) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'When hinting a commit ("%s") as rewritten, you must provide '.
|
||||||
|
'the commit it was rewritten into.',
|
||||||
|
$old));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case self::HINT_UNREADABLE:
|
||||||
|
if ($new) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'When hinting a commit ("%s") as unreadable, you must not '.
|
||||||
|
'provide a new commit ("%s").',
|
||||||
|
$old,
|
||||||
|
$new));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$all_types = self::getAllHintTypes();
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Hint type ("%s") for commit ("%s") is not valid. Valid hints '.
|
||||||
|
'are: %s.',
|
||||||
|
$type,
|
||||||
|
$old,
|
||||||
|
implode(', ', $all_types)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = new self();
|
||||||
|
$table_name = $table->getTableName();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
if ($type == self::HINT_NONE) {
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'DELETE FROM %T WHERE repositoryPHID = %s AND oldCommitIdentifier = %s',
|
||||||
|
$table_name,
|
||||||
|
$repository_phid,
|
||||||
|
$old);
|
||||||
|
} else {
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'INSERT INTO %T
|
||||||
|
(repositoryPHID, oldCommitIdentifier, newCommitIdentifier, hintType)
|
||||||
|
VALUES (%s, %s, %ns, %s)
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
newCommitIdentifier = VALUES(newCommitIdentifier),
|
||||||
|
hintType = VALUES(hintType)',
|
||||||
|
$table_name,
|
||||||
|
$repository_phid,
|
||||||
|
$old,
|
||||||
|
$new,
|
||||||
|
$type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue