1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Add HarbormasterRunnerWorker, for running CI tests

Summary:
This is very preliminary and doesn't actually do anything useful. In theory, it uses Drydock to check out a working copy and run tests. In practice, it's not actually capable of running any of our tests (because of complicated interdependency stuff), but does check out a working copy and //try// to run tests there.

Adds various sorts of utility methods to various things as well.

Test Plan: Ran `reparse.php --harbormaster --trace <commit>`, observed attempt to run tests via Drydock.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2015, T1049

Differential Revision: https://secure.phabricator.com/D4215
This commit is contained in:
epriestley 2012-12-17 13:43:26 -08:00
parent 5cd39b3964
commit adfe84ffce
9 changed files with 142 additions and 5 deletions

View file

@ -55,6 +55,10 @@ $args->parse(
'delete existing relationship entries between your '. 'delete existing relationship entries between your '.
'package and some old commits!)', 'package and some old commits!)',
), ),
array(
'name' => 'harbormaster',
'help' => 'EXPERIMENTAL. Execute Harbormaster.',
),
// misc options // misc options
array( array(
'name' => 'force', 'name' => 'force',
@ -73,6 +77,7 @@ $reparse_message = $args->getArg('message');
$reparse_change = $args->getArg('change'); $reparse_change = $args->getArg('change');
$reparse_herald = $args->getArg('herald'); $reparse_herald = $args->getArg('herald');
$reparse_owners = $args->getArg('owners'); $reparse_owners = $args->getArg('owners');
$reparse_harbormaster = $args->getArg('harbormaster');
$reparse_what = $args->getArg('revision'); $reparse_what = $args->getArg('revision');
$force = $args->getArg('force'); $force = $args->getArg('force');
$force_local = $args->getArg('force-local'); $force_local = $args->getArg('force-local');
@ -83,9 +88,9 @@ if (!$all_from_repo && !$reparse_what) {
} }
if (!$reparse_message && !$reparse_change && !$reparse_herald && if (!$reparse_message && !$reparse_change && !$reparse_herald &&
!$reparse_owners) { !$reparse_owners && !$reparse_harbormaster) {
usage("Specify what information to reparse with --message, --change, ". usage("Specify what information to reparse with --message, --change, ".
"--herald, and/or --owners"); "--herald, --harbormaster, and/or --owners");
} }
if ($reparse_owners && !$force) { if ($reparse_owners && !$force) {
echo phutil_console_wrap( echo phutil_console_wrap(
@ -202,6 +207,10 @@ foreach ($commits as $commit) {
$classes[] = 'PhabricatorRepositoryCommitOwnersWorker'; $classes[] = 'PhabricatorRepositoryCommitOwnersWorker';
} }
if ($reparse_harbormaster) {
$classes[] = 'HarbormasterRunnerWorker';
}
$spec = array( $spec = array(
'commitID' => $commit->getID(), 'commitID' => $commit->getID(),
'only' => true, 'only' => true,
@ -218,7 +227,7 @@ foreach ($commits as $commit) {
foreach ($classes as $class) { foreach ($classes as $class) {
$worker = newv($class, array($spec)); $worker = newv($class, array($spec));
echo "Running '{$class}'...\n"; echo "Running '{$class}'...\n";
$worker->doWork(); $worker->executeTask();
} }
} }
} }

View file

@ -456,6 +456,7 @@ phutil_register_library_map(array(
'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php', 'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php',
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php',
'HarbormasterRunnerWorker' => 'applications/harbormaster/worker/HarbormasterRunnerWorker.php',
'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php', 'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php',
'HeraldAction' => 'applications/herald/storage/HeraldAction.php', 'HeraldAction' => 'applications/herald/storage/HeraldAction.php',
'HeraldActionConfig' => 'applications/herald/config/HeraldActionConfig.php', 'HeraldActionConfig' => 'applications/herald/config/HeraldActionConfig.php',
@ -1744,6 +1745,7 @@ phutil_register_library_map(array(
'FeedPublisherWorker' => 'PhabricatorWorker', 'FeedPublisherWorker' => 'PhabricatorWorker',
'HarbormasterDAO' => 'PhabricatorLiskDAO', 'HarbormasterDAO' => 'PhabricatorLiskDAO',
'HarbormasterObject' => 'HarbormasterDAO', 'HarbormasterObject' => 'HarbormasterDAO',
'HarbormasterRunnerWorker' => 'PhabricatorWorker',
'HarbormasterScratchTable' => 'HarbormasterDAO', 'HarbormasterScratchTable' => 'HarbormasterDAO',
'HeraldAction' => 'HeraldDAO', 'HeraldAction' => 'HeraldDAO',
'HeraldApplyTranscript' => 'HeraldDAO', 'HeraldApplyTranscript' => 'HeraldDAO',

View file

@ -22,6 +22,17 @@ abstract class DrydockBlueprint {
return get_class($this); return get_class($this);
} }
protected function loadLease($lease_id) {
$lease = id(new DrydockLease())->load($lease_id);
if (!$lease) {
throw new Exception("No such lease '{$lease_id}'!");
}
$resource = $lease->loadResource();
$lease->attachResource($resource);
return $lease;
}
/* -( Lease Acquisition )-------------------------------------------------- */ /* -( Lease Acquisition )-------------------------------------------------- */

View file

@ -86,6 +86,13 @@ final class DrydockWorkingCopyBlueprint extends DrydockBlueprint {
DrydockLease $lease, DrydockLease $lease,
$type) { $type) {
switch ($type) {
case 'command':
return $this
->loadLease($resource->getAttribute('lease.host'))
->getInterface($type);
}
throw new Exception("No interface of type '{$type}'."); throw new Exception("No interface of type '{$type}'.");
} }

View file

@ -2,6 +2,17 @@
abstract class DrydockCommandInterface extends DrydockInterface { abstract class DrydockCommandInterface extends DrydockInterface {
private $workingDirectory;
public function setWorkingDirectory($working_directory) {
$this->workingDirectory = $working_directory;
return $this;
}
public function getWorkingDirectory() {
return $this->workingDirectory;
}
final public function getInterfaceType() { final public function getInterfaceType() {
return 'command'; return 'command';
} }
@ -24,4 +35,17 @@ abstract class DrydockCommandInterface extends DrydockInterface {
abstract public function getExecFuture($command); abstract public function getExecFuture($command);
protected function applyWorkingDirectoryToArgv(array $argv) {
if ($this->getWorkingDirectory() !== null) {
$cmd = $argv[0];
$cmd = "(cd %s; {$cmd})";
$argv = array_merge(
array($cmd),
array($this->getWorkingDirectory()),
array_slice($argv, 1));
}
return $argv;
}
} }

View file

@ -4,6 +4,8 @@ final class DrydockLocalCommandInterface extends DrydockCommandInterface {
public function getExecFuture($command) { public function getExecFuture($command) {
$argv = func_get_args(); $argv = func_get_args();
$argv = $this->applyWorkingDirectoryToArgv($argv);
return newv('ExecFuture', $argv); return newv('ExecFuture', $argv);
} }

View file

@ -4,6 +4,8 @@ final class DrydockSSHCommandInterface extends DrydockCommandInterface {
public function getExecFuture($command) { public function getExecFuture($command) {
$argv = func_get_args(); $argv = func_get_args();
$argv = $this->applyWorkingDirectoryToArgv($argv);
$full_command = call_user_func_array('csprintf', $argv); $full_command = call_user_func_array('csprintf', $argv);
// NOTE: The "-t -t" is for psuedo-tty allocation so we can "sudo" on some // NOTE: The "-t -t" is for psuedo-tty allocation so we can "sudo" on some

View file

@ -11,6 +11,26 @@ final class DrydockLease extends DrydockDAO {
protected $taskID; protected $taskID;
private $resource; private $resource;
private $releaseOnDestruction;
/**
* Flag this lease to be released when its destructor is called. This is
* mostly useful if you have a script which acquires, uses, and then releases
* a lease, as you don't need to explicitly handle exceptions to properly
* release the lease.
*/
public function releaseOnDestruction() {
$this->releaseOnDestruction = true;
return $this;
}
public function __destruct() {
if ($this->releaseOnDestruction) {
if ($this->isActive()) {
$this->release();
}
}
}
public function getLeaseName() { public function getLeaseName() {
return pht('Lease %d', $this->getID()); return pht('Lease %d', $this->getID());
@ -103,9 +123,17 @@ final class DrydockLease extends DrydockDAO {
return $this; return $this;
} }
private function isActive() {
switch ($this->status) {
case DrydockLeaseStatus::STATUS_ACTIVE:
case DrydockLeaseStatus::STATUS_ACQUIRING:
return true;
}
return false;
}
private function assertActive() { private function assertActive() {
if (($this->status != DrydockLeaseStatus::STATUS_ACTIVE) && if (!$this->isActive()) {
($this->status != DrydockLeaseStatus::STATUS_ACQUIRING)) {
throw new Exception( throw new Exception(
"Lease is not active! You can not interact with resources through ". "Lease is not active! You can not interact with resources through ".
"an inactive lease."); "an inactive lease.");

View file

@ -0,0 +1,52 @@
<?php
final class HarbormasterRunnerWorker extends PhabricatorWorker {
public function getRequiredLeaseTime() {
return 60 * 60 * 24;
}
protected function doWork() {
$data = $this->getTaskData();
$id = idx($data, 'commitID');
$commit = id(new PhabricatorRepositoryCommit())->loadOneWhere(
'id = %d',
$id);
if (!$commit) {
throw new PhabricatorWorkerPermanentFailureException(
"Commit '{$id}' does not exist!");
}
$repository = id(new PhabricatorRepository())->loadOneWhere(
'id = %d',
$commit->getRepositoryID());
if (!$repository) {
throw new PhabricatorWorkerPermanentFailureException(
"Unable to load repository for commit '{$id}'!");
}
$lease = id(new DrydockLease())
->setResourceType('working-copy')
->setAttributes(
array(
'repositoryID' => $repository->getID(),
'commit' => $commit->getCommitIdentifier(),
))
->releaseOnDestruction()
->waitUntilActive();
$cmd = $lease->getInterface('command');
list($json) = $cmd
->setWorkingDirectory($lease->getResource()->getAttribute('path'))
->execx('arc unit --everything --json');
$lease->release();
// TODO: Do something actually useful with this. Requires Harbormaster
// buildout.
echo $json;
}
}