mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 22:10:55 +01:00
Improve lipsum generation of projects
Summary: Fixes T9156. - Fix hashtag generation. - Fix various badnesses. - Improve project name generator. Test Plan: ``` $ ./bin/lipsum generate projects GENERATORS Selected generators: Projects. WARNING This command generates synthetic test data, including user accounts. It is intended for use in development environments so you can test features more easily. There is no easy way to delete this data or undo the effects of this command. If you run it in a production environment, it will pollute your data with large amounts of meaningless garbage that you can not get rid of. Are you sure you want to generate piles of garbage? [y/N] y LIPSUM Generating synthetic test objects forever. Use ^C to stop when satisfied. Generated "Project": Self-Flying Data Center Swag Performance Generated "Project": Optimize Cars Generated "Project": Triaging Culture Optimization Generated "Project": Automating Experience Generated "Project": Accelerating NUX Performance Generated "Project": Optimizing Culture Optimization Generated "Project": Optimize Hardware ``` {F1042949} Reviewers: chad Reviewed By: chad Maniphest Tasks: T9156 Differential Revision: https://secure.phabricator.com/D14874
This commit is contained in:
parent
ba37149bf9
commit
19b2eb57a9
7 changed files with 221 additions and 59 deletions
|
@ -2862,6 +2862,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php',
|
'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php',
|
||||||
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
||||||
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
|
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
|
||||||
|
'PhabricatorProjectNameContextFreeGrammar' => 'applications/project/lipsum/PhabricatorProjectNameContextFreeGrammar.php',
|
||||||
'PhabricatorProjectNoProjectsDatasource' => 'applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php',
|
'PhabricatorProjectNoProjectsDatasource' => 'applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php',
|
||||||
'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php',
|
'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php',
|
||||||
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
|
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
|
||||||
|
@ -7199,6 +7200,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule',
|
'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule',
|
||||||
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
|
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
|
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
|
||||||
|
'PhabricatorProjectNameContextFreeGrammar' => 'PhutilContextFreeGrammar',
|
||||||
'PhabricatorProjectNoProjectsDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorProjectNoProjectsDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType',
|
||||||
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
|
|
|
@ -27,13 +27,10 @@ final class PhabricatorDifferentialRevisionTestDataGenerator
|
||||||
->setTransactionType(DifferentialTransaction::TYPE_UPDATE)
|
->setTransactionType(DifferentialTransaction::TYPE_UPDATE)
|
||||||
->setNewValue($diff->getPHID());
|
->setNewValue($diff->getPHID());
|
||||||
|
|
||||||
$content_source = PhabricatorContentSource::newForSource(
|
|
||||||
PhabricatorContentSource::SOURCE_LIPSUM,
|
|
||||||
array());
|
|
||||||
|
|
||||||
id(new DifferentialTransactionEditor())
|
id(new DifferentialTransactionEditor())
|
||||||
->setActor($author)
|
->setActor($author)
|
||||||
->setContentSource($content_source)
|
->setContentSource($this->getLipsumContentSource())
|
||||||
->applyTransactions($revision, $xactions);
|
->applyTransactions($revision, $xactions);
|
||||||
|
|
||||||
return $revision;
|
return $revision;
|
||||||
|
|
|
@ -2,9 +2,81 @@
|
||||||
|
|
||||||
abstract class PhabricatorTestDataGenerator extends Phobject {
|
abstract class PhabricatorTestDataGenerator extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
abstract public function getGeneratorName();
|
abstract public function getGeneratorName();
|
||||||
abstract public function generateObject();
|
abstract public function generateObject();
|
||||||
|
|
||||||
|
final public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadRandomPHID($table) {
|
||||||
|
$conn_r = $table->establishConnection('r');
|
||||||
|
|
||||||
|
$row = queryfx_one(
|
||||||
|
$conn_r,
|
||||||
|
'SELECT phid FROM %T ORDER BY RAND() LIMIT 1',
|
||||||
|
$table->getTableName());
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row['phid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadRandomUser() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$user_phid = $this->loadRandomPHID(new PhabricatorUser());
|
||||||
|
|
||||||
|
$user = null;
|
||||||
|
if ($user_phid) {
|
||||||
|
$user = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($user_phid))
|
||||||
|
->executeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to load a random user. You may need to generate more '.
|
||||||
|
'test users first.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getLipsumContentSource() {
|
||||||
|
return PhabricatorContentSource::newForSource(
|
||||||
|
PhabricatorContentSource::SOURCE_LIPSUM,
|
||||||
|
array());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roll `n` dice with `d` sides each, then add `bonus` and return the sum.
|
||||||
|
*/
|
||||||
|
protected function roll($n, $d, $bonus = 0) {
|
||||||
|
$sum = 0;
|
||||||
|
for ($ii = 0; $ii < $n; $ii++) {
|
||||||
|
$sum += mt_rand(1, $d);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum += $bonus;
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function loadOneRandom($classname) {
|
public function loadOneRandom($classname) {
|
||||||
try {
|
try {
|
||||||
return newv($classname, array())
|
return newv($classname, array())
|
||||||
|
@ -26,4 +98,5 @@ abstract class PhabricatorTestDataGenerator extends Phobject {
|
||||||
return $this->loadOneRandom('PhabricatorUser');
|
return $this->loadOneRandom('PhabricatorUser');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,10 +120,30 @@ final class PhabricatorLipsumGenerateWorkflow
|
||||||
protected function generate(array $generators) {
|
protected function generate(array $generators) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
foreach ($generators as $generator) {
|
||||||
|
$generator->setViewer($this->getViewer());
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$generator = $generators[array_rand($generators)];
|
$generator = $generators[array_rand($generators)];
|
||||||
|
|
||||||
$object = $generator->generateObject();
|
try {
|
||||||
|
$object = $generator->generateObject();
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
echo tsprintf(
|
||||||
|
"**<bg:yellow> %s </bg>** %s\n",
|
||||||
|
pht('OOPS'),
|
||||||
|
pht(
|
||||||
|
'Generator ("%s") was unable to generate an object.',
|
||||||
|
$generator->getGeneratorName()));
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%B\n",
|
||||||
|
$ex->getMessage());
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$object_phid = $object->getPHID();
|
$object_phid = $object->getPHID();
|
||||||
|
|
||||||
$handles = $viewer->loadHandles(array($object_phid));
|
$handles = $viewer->loadHandles(array($object_phid));
|
||||||
|
|
|
@ -76,14 +76,12 @@ final class PhabricatorObjectMailReceiverTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildMail($style) {
|
private function buildMail($style) {
|
||||||
|
|
||||||
// TODO: Clean up test data generators so that we don't need to guarantee
|
|
||||||
// the existence of a user.
|
|
||||||
$this->generateNewTestUser();
|
|
||||||
|
|
||||||
$task = id(new PhabricatorManiphestTaskTestDataGenerator())->generate();
|
|
||||||
$user = $this->generateNewTestUser();
|
$user = $this->generateNewTestUser();
|
||||||
|
|
||||||
|
$task = id(new PhabricatorManiphestTaskTestDataGenerator())
|
||||||
|
->setViewer($user)
|
||||||
|
->generateObject();
|
||||||
|
|
||||||
$is_public = ($style === 'public');
|
$is_public = ($style === 'public');
|
||||||
$is_bad_hash = ($style == 'badhash');
|
$is_bad_hash = ($style == 'badhash');
|
||||||
$is_bad_user = ($style == 'baduser');
|
$is_bad_user = ($style == 'baduser');
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectNameContextFreeGrammar
|
||||||
|
extends PhutilContextFreeGrammar {
|
||||||
|
|
||||||
|
protected function getRules() {
|
||||||
|
return array(
|
||||||
|
'start' => array(
|
||||||
|
'[project]',
|
||||||
|
'[project] [tion]',
|
||||||
|
'[action] [project]',
|
||||||
|
'[action] [project] [tion]',
|
||||||
|
),
|
||||||
|
'project' => array(
|
||||||
|
'Backend',
|
||||||
|
'Frontend',
|
||||||
|
'Web',
|
||||||
|
'Mobile',
|
||||||
|
'Tablet',
|
||||||
|
'Robot',
|
||||||
|
'NUX',
|
||||||
|
'Cars',
|
||||||
|
'Drones',
|
||||||
|
'Experience',
|
||||||
|
'Swag',
|
||||||
|
'Security',
|
||||||
|
'Culture',
|
||||||
|
'Revenue',
|
||||||
|
'Ion Cannon',
|
||||||
|
'Graphics Engine',
|
||||||
|
'Drivers',
|
||||||
|
'Audio Drivers',
|
||||||
|
'Graphics Drivers',
|
||||||
|
'Hardware',
|
||||||
|
'Data Center',
|
||||||
|
'[project] [project]',
|
||||||
|
'[adjective] [project]',
|
||||||
|
'[adjective] [project]',
|
||||||
|
),
|
||||||
|
'adjective' => array(
|
||||||
|
'Self-Driving',
|
||||||
|
'Self-Flying',
|
||||||
|
'Self-Immolating',
|
||||||
|
'Secure',
|
||||||
|
'Insecure',
|
||||||
|
'Somewhat-Secure',
|
||||||
|
'Orbital',
|
||||||
|
'Next-Generation',
|
||||||
|
),
|
||||||
|
'tion' => array(
|
||||||
|
'Automation',
|
||||||
|
'Optimization',
|
||||||
|
'Performance',
|
||||||
|
'Improvement',
|
||||||
|
'Growth',
|
||||||
|
'Monetization',
|
||||||
|
),
|
||||||
|
'action' => array(
|
||||||
|
'Monetize',
|
||||||
|
'Monetize',
|
||||||
|
'Triage',
|
||||||
|
'Triaging',
|
||||||
|
'Automate',
|
||||||
|
'Automating',
|
||||||
|
'Improve',
|
||||||
|
'Improving',
|
||||||
|
'Optimize',
|
||||||
|
'Optimizing',
|
||||||
|
'Accelerate',
|
||||||
|
'Accelerating',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,79 +3,76 @@
|
||||||
final class PhabricatorProjectTestDataGenerator
|
final class PhabricatorProjectTestDataGenerator
|
||||||
extends PhabricatorTestDataGenerator {
|
extends PhabricatorTestDataGenerator {
|
||||||
|
|
||||||
private $xactions = array();
|
|
||||||
|
|
||||||
public function getGeneratorName() {
|
public function getGeneratorName() {
|
||||||
return pht('Projects');
|
return pht('Projects');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateObject() {
|
public function generateObject() {
|
||||||
$title = $this->generateTitle();
|
$author = $this->loadRandomUser();
|
||||||
$author = $this->loadPhabrictorUser();
|
$project = PhabricatorProject::initializeNewProject($author);
|
||||||
$author_phid = $author->getPHID();
|
|
||||||
$project = PhabricatorProject::initializeNewProject($author)
|
|
||||||
->setName($title);
|
|
||||||
|
|
||||||
$this->addTransaction(
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $this->newTransaction(
|
||||||
PhabricatorProjectTransaction::TYPE_NAME,
|
PhabricatorProjectTransaction::TYPE_NAME,
|
||||||
$title);
|
$this->newProjectTitle());
|
||||||
$project->attachMemberPHIDs(
|
|
||||||
$this->loadMembersWithAuthor($author_phid));
|
$xactions[] = $this->newTransaction(
|
||||||
$this->addTransaction(
|
|
||||||
PhabricatorProjectTransaction::TYPE_STATUS,
|
PhabricatorProjectTransaction::TYPE_STATUS,
|
||||||
$this->generateProjectStatus());
|
$this->newProjectStatus());
|
||||||
$this->addTransaction(
|
|
||||||
PhabricatorTransactions::TYPE_VIEW_POLICY,
|
// Almost always make the author a member.
|
||||||
PhabricatorPolicies::POLICY_PUBLIC);
|
$members = array();
|
||||||
$this->addTransaction(
|
if ($this->roll(1, 20) > 2) {
|
||||||
PhabricatorTransactions::TYPE_EDIT_POLICY,
|
$members[] = $author->getPHID();
|
||||||
PhabricatorPolicies::POLICY_PUBLIC);
|
}
|
||||||
$this->addTransaction(
|
|
||||||
PhabricatorTransactions::TYPE_JOIN_POLICY,
|
// Add a few other members.
|
||||||
PhabricatorPolicies::POLICY_PUBLIC);
|
$size = $this->roll(2, 6, -2);
|
||||||
|
for ($ii = 0; $ii < $size; $ii++) {
|
||||||
|
$members[] = $this->loadRandomUser()->getPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
$xactions[] = $this->newTransaction(
|
||||||
|
PhabricatorTransactions::TYPE_EDGE,
|
||||||
|
array(
|
||||||
|
'+' => array_fuse($members),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'edge:type' => PhabricatorProjectProjectHasMemberEdgeType::EDGECONST,
|
||||||
|
));
|
||||||
|
|
||||||
$editor = id(new PhabricatorProjectTransactionEditor())
|
$editor = id(new PhabricatorProjectTransactionEditor())
|
||||||
->setActor($author)
|
->setActor($author)
|
||||||
->setContentSource(PhabricatorContentSource::newConsoleSource())
|
->setContentSource($this->getLipsumContentSource())
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
->applyTransactions($project, $this->xactions);
|
->applyTransactions($project, $xactions);
|
||||||
|
|
||||||
return $project->save();
|
return $project;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addTransaction($type, $value) {
|
private function newTransaction($type, $value, $metadata = array()) {
|
||||||
$this->xactions[] = id(new PhabricatorProjectTransaction())
|
$xaction = id(new PhabricatorProjectTransaction())
|
||||||
->setTransactionType($type)
|
->setTransactionType($type)
|
||||||
->setNewValue($value);
|
->setNewValue($value);
|
||||||
}
|
|
||||||
|
|
||||||
|
foreach ($metadata as $key => $value) {
|
||||||
public function loadMembersWithAuthor($author) {
|
$xaction->setMetadataValue($key, $value);
|
||||||
$members = array($author);
|
|
||||||
for ($i = 0; $i < rand(10, 20);$i++) {
|
|
||||||
$members[] = $this->loadPhabrictorUserPHID();
|
|
||||||
}
|
}
|
||||||
return $members;
|
|
||||||
|
return $xaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateTitle() {
|
public function newProjectTitle() {
|
||||||
return id(new PhutilLipsumContextFreeGrammar())
|
return id(new PhabricatorProjectNameContextFreeGrammar())
|
||||||
->generate();
|
->generate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateDescription() {
|
public function newProjectStatus() {
|
||||||
return id(new PhutilLipsumContextFreeGrammar())
|
if ($this->roll(1, 20) > 5) {
|
||||||
->generateSeveral(rand(30, 40));
|
return PhabricatorProjectStatus::STATUS_ACTIVE;
|
||||||
}
|
|
||||||
|
|
||||||
public function generateProjectStatus() {
|
|
||||||
$statuses = array_keys(PhabricatorProjectStatus::getStatusMap());
|
|
||||||
// Make sure 4/5th of all generated Projects are active
|
|
||||||
$random = rand(0, 4);
|
|
||||||
if ($random != 0) {
|
|
||||||
return $statuses[0];
|
|
||||||
} else {
|
} else {
|
||||||
return $statuses[1];
|
return PhabricatorProjectStatus::STATUS_ARCHIVED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue