mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-19 12:00:55 +01:00
Allow Harbormaster to lease working copies from Drydock
Summary: Ref T9252. This is still crude in a few ways but basically works, at least for commits. Test Plan: - Made a build plan with just this build step. - Ran `bin/harbormaster build --plan 10 ...` on a commit. - It actually built a working copy, leased it, took no action, and released the lease. MAGIC~~~ Reviewers: chad Reviewed By: chad Maniphest Tasks: T9252 Differential Revision: https://secure.phabricator.com/D14160
This commit is contained in:
parent
381fa611fd
commit
284fe0fe51
10 changed files with 225 additions and 74 deletions
|
@ -1002,11 +1002,13 @@ phutil_register_library_map(array(
|
|||
'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php',
|
||||
'HarbormasterCreateArtifactConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterCreateArtifactConduitAPIMethod.php',
|
||||
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
|
||||
'HarbormasterDrydockLeaseArtifact' => 'applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php',
|
||||
'HarbormasterExternalBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterExternalBuildStepGroup.php',
|
||||
'HarbormasterFileArtifact' => 'applications/harbormaster/artifact/HarbormasterFileArtifact.php',
|
||||
'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php',
|
||||
'HarbormasterHostArtifact' => 'applications/harbormaster/artifact/HarbormasterHostArtifact.php',
|
||||
'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php',
|
||||
'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php',
|
||||
'HarbormasterLintMessagesController' => 'applications/harbormaster/controller/HarbormasterLintMessagesController.php',
|
||||
'HarbormasterLintPropertyView' => 'applications/harbormaster/view/HarbormasterLintPropertyView.php',
|
||||
'HarbormasterManagePlansCapability' => 'applications/harbormaster/capability/HarbormasterManagePlansCapability.php',
|
||||
|
@ -1047,6 +1049,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterUploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php',
|
||||
'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php',
|
||||
'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php',
|
||||
'HarbormasterWorkingCopyArtifact' => 'applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php',
|
||||
'HeraldAction' => 'applications/herald/action/HeraldAction.php',
|
||||
'HeraldActionGroup' => 'applications/herald/action/HeraldActionGroup.php',
|
||||
'HeraldActionRecord' => 'applications/herald/storage/HeraldActionRecord.php',
|
||||
|
@ -4786,11 +4789,13 @@ phutil_register_library_map(array(
|
|||
'HarbormasterController' => 'PhabricatorController',
|
||||
'HarbormasterCreateArtifactConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
||||
'HarbormasterDAO' => 'PhabricatorLiskDAO',
|
||||
'HarbormasterDrydockLeaseArtifact' => 'HarbormasterArtifact',
|
||||
'HarbormasterExternalBuildStepGroup' => 'HarbormasterBuildStepGroup',
|
||||
'HarbormasterFileArtifact' => 'HarbormasterArtifact',
|
||||
'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterHostArtifact' => 'HarbormasterArtifact',
|
||||
'HarbormasterHostArtifact' => 'HarbormasterDrydockLeaseArtifact',
|
||||
'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterLintMessagesController' => 'HarbormasterController',
|
||||
'HarbormasterLintPropertyView' => 'AphrontView',
|
||||
'HarbormasterManagePlansCapability' => 'PhabricatorPolicyCapability',
|
||||
|
@ -4831,6 +4836,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterUploadArtifactBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterWorker' => 'PhabricatorWorker',
|
||||
'HarbormasterWorkingCopyArtifact' => 'HarbormasterDrydockLeaseArtifact',
|
||||
'HeraldAction' => 'Phobject',
|
||||
'HeraldActionGroup' => 'HeraldGroup',
|
||||
'HeraldActionRecord' => 'HeraldDAO',
|
||||
|
|
|
@ -443,6 +443,7 @@ final class DifferentialDiff
|
|||
|
||||
if ($repo) {
|
||||
$results['repository.callsign'] = $repo->getCallsign();
|
||||
$results['repository.phid'] = $repo->getPHID();
|
||||
$results['repository.vcs'] = $repo->getVersionControlSystem();
|
||||
$results['repository.uri'] = $repo->getPublicCloneURI();
|
||||
}
|
||||
|
@ -459,6 +460,8 @@ final class DifferentialDiff
|
|||
pht('The differential revision ID, if applicable.'),
|
||||
'repository.callsign' =>
|
||||
pht('The callsign of the repository in Phabricator.'),
|
||||
'repository.phid' =>
|
||||
pht('The PHID of the repository in Phabricator.'),
|
||||
'repository.vcs' =>
|
||||
pht('The version control system, either "svn", "hg" or "git".'),
|
||||
'repository.uri' =>
|
||||
|
|
|
@ -126,22 +126,23 @@ final class DrydockLease extends DrydockDAO
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function isActive() {
|
||||
switch ($this->status) {
|
||||
public function isActivating() {
|
||||
switch ($this->getStatus()) {
|
||||
case DrydockLeaseStatus::STATUS_PENDING:
|
||||
case DrydockLeaseStatus::STATUS_ACQUIRED:
|
||||
case DrydockLeaseStatus::STATUS_ACTIVE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function assertActive() {
|
||||
if (!$this->isActive()) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Lease is not active! You can not interact with resources through '.
|
||||
'an inactive lease.'));
|
||||
public function isActive() {
|
||||
switch ($this->getStatus()) {
|
||||
case DrydockLeaseStatus::STATUS_ACTIVE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function waitUntilActive() {
|
||||
|
|
|
@ -41,7 +41,10 @@ final class DrydockLeaseListView extends AphrontView {
|
|||
$item->addAttribute($status);
|
||||
$item->setEpoch($lease->getDateCreated());
|
||||
|
||||
if ($lease->isActive()) {
|
||||
// TODO: Tailor this for clarity.
|
||||
if ($lease->isActivating()) {
|
||||
$item->setStatusIcon('fa-dot-circle-o yellow');
|
||||
} else if ($lease->isActive()) {
|
||||
$item->setStatusIcon('fa-dot-circle-o green');
|
||||
} else {
|
||||
$item->setStatusIcon('fa-dot-circle-o red');
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
abstract class HarbormasterDrydockLeaseArtifact
|
||||
extends HarbormasterArtifact {
|
||||
|
||||
public function getArtifactParameterSpecification() {
|
||||
return array(
|
||||
'drydockLeasePHID' => 'string',
|
||||
);
|
||||
}
|
||||
|
||||
public function getArtifactParameterDescriptions() {
|
||||
return array(
|
||||
'drydockLeasePHID' => pht(
|
||||
'Drydock working copy lease to create an artifact from.'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getArtifactDataExample() {
|
||||
return array(
|
||||
'drydockLeasePHID' => 'PHID-DRYL-abcdefghijklmnopqrst',
|
||||
);
|
||||
}
|
||||
|
||||
public function renderArtifactSummary(PhabricatorUser $viewer) {
|
||||
$artifact = $this->getBuildArtifact();
|
||||
$lease_phid = $artifact->getProperty('drydockLeasePHID');
|
||||
return $viewer->renderHandle($lease_phid);
|
||||
}
|
||||
|
||||
public function willCreateArtifact(PhabricatorUser $actor) {
|
||||
$this->loadArtifactLease($actor);
|
||||
}
|
||||
|
||||
public function loadArtifactLease(PhabricatorUser $viewer) {
|
||||
$artifact = $this->getBuildArtifact();
|
||||
$lease_phid = $artifact->getProperty('drydockLeasePHID');
|
||||
|
||||
$lease = id(new DrydockLeaseQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($lease_phid))
|
||||
->executeOne();
|
||||
if (!$lease) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Drydock lease PHID "%s" does not correspond to a valid lease.',
|
||||
$lease_phid));
|
||||
}
|
||||
|
||||
return $lease;
|
||||
}
|
||||
|
||||
public function releaseArtifact(PhabricatorUser $actor) {
|
||||
$lease = $this->loadArtifactLease($actor);
|
||||
if (!$lease->canRelease()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$author_phid = $actor->getPHID();
|
||||
if (!$author_phid) {
|
||||
$author_phid = id(new PhabricatorHarbormasterApplication())->getPHID();
|
||||
}
|
||||
|
||||
$command = DrydockCommand::initializeNewCommand($actor)
|
||||
->setTargetPHID($lease->getPHID())
|
||||
->setAuthorPHID($author_phid)
|
||||
->setCommand(DrydockCommand::COMMAND_RELEASE)
|
||||
->save();
|
||||
|
||||
$lease->scheduleUpdate();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterHostArtifact extends HarbormasterArtifact {
|
||||
final class HarbormasterHostArtifact
|
||||
extends HarbormasterDrydockLeaseArtifact {
|
||||
|
||||
const ARTIFACTCONST = 'host';
|
||||
|
||||
|
@ -12,66 +13,4 @@ final class HarbormasterHostArtifact extends HarbormasterArtifact {
|
|||
return pht('References a host lease from Drydock.');
|
||||
}
|
||||
|
||||
|
||||
public function getArtifactParameterSpecification() {
|
||||
return array(
|
||||
'drydockLeasePHID' => 'string',
|
||||
);
|
||||
}
|
||||
|
||||
public function getArtifactParameterDescriptions() {
|
||||
return array(
|
||||
'drydockLeasePHID' => pht(
|
||||
'Drydock host lease to create an artifact from.'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getArtifactDataExample() {
|
||||
return array(
|
||||
'drydockLeasePHID' => 'PHID-DRYL-abcdefghijklmnopqrst',
|
||||
);
|
||||
}
|
||||
|
||||
public function renderArtifactSummary(PhabricatorUser $viewer) {
|
||||
$artifact = $this->getBuildArtifact();
|
||||
$file_phid = $artifact->getProperty('drydockLeasePHID');
|
||||
return $viewer->renderHandle($file_phid);
|
||||
}
|
||||
|
||||
public function willCreateArtifact(PhabricatorUser $actor) {
|
||||
$this->loadArtifactLease($actor);
|
||||
}
|
||||
|
||||
public function loadArtifactLease(PhabricatorUser $viewer) {
|
||||
$artifact = $this->getBuildArtifact();
|
||||
$lease_phid = $artifact->getProperty('drydockLeasePHID');
|
||||
|
||||
$lease = id(new DrydockLeaseQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($lease_phid))
|
||||
->executeOne();
|
||||
if (!$lease) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Drydock lease PHID "%s" does not correspond to a valid lease.',
|
||||
$lease_phid));
|
||||
}
|
||||
|
||||
return $lease;
|
||||
}
|
||||
|
||||
public function releaseArtifact(PhabricatorUser $actor) {
|
||||
$lease = $this->loadArtifactLease($actor);
|
||||
if (!$lease->canRelease()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$command = DrydockCommand::initializeNewCommand($actor)
|
||||
->setTargetPHID($lease->getPHID())
|
||||
->setCommand(DrydockCommand::COMMAND_RELEASE)
|
||||
->save();
|
||||
|
||||
$lease->scheduleUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterWorkingCopyArtifact
|
||||
extends HarbormasterDrydockLeaseArtifact {
|
||||
|
||||
const ARTIFACTCONST = 'working-copy';
|
||||
|
||||
public function getArtifactTypeName() {
|
||||
return pht('Drydock Working Copy');
|
||||
}
|
||||
|
||||
public function getArtifactTypeDescription() {
|
||||
return pht('References a working copy lease from Drydock.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterLeaseWorkingCopyBuildStepImplementation
|
||||
extends HarbormasterBuildStepImplementation {
|
||||
|
||||
public function getName() {
|
||||
return pht('Lease Working Copy');
|
||||
}
|
||||
|
||||
public function getGenericDescription() {
|
||||
return pht('Build a working copy in Drydock.');
|
||||
}
|
||||
|
||||
public function getBuildStepGroupKey() {
|
||||
return HarbormasterPrototypeBuildStepGroup::GROUPKEY;
|
||||
}
|
||||
|
||||
public function execute(
|
||||
HarbormasterBuild $build,
|
||||
HarbormasterBuildTarget $build_target) {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$settings = $this->getSettings();
|
||||
|
||||
// TODO: We should probably have a separate temporary storage area for
|
||||
// execution stuff that doesn't step on configuration state?
|
||||
$lease_phid = $build_target->getDetail('exec.leasePHID');
|
||||
|
||||
if ($lease_phid) {
|
||||
$lease = id(new DrydockLeaseQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($lease_phid))
|
||||
->executeOne();
|
||||
if (!$lease) {
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
pht(
|
||||
'Lease "%s" could not be loaded.',
|
||||
$lease_phid));
|
||||
}
|
||||
} else {
|
||||
$working_copy_type = id(new DrydockWorkingCopyBlueprintImplementation())
|
||||
->getType();
|
||||
|
||||
$lease = id(new DrydockLease())
|
||||
->setResourceType($working_copy_type)
|
||||
->setOwnerPHID($build_target->getPHID());
|
||||
|
||||
$variables = $build_target->getVariables();
|
||||
|
||||
$repository_phid = idx($variables, 'repository.phid');
|
||||
$commit = idx($variables, 'repository.commit');
|
||||
|
||||
$lease
|
||||
->setAttribute('repositoryPHID', $repository_phid)
|
||||
->setAttribute('commit', $commit);
|
||||
|
||||
$lease->queueForActivation();
|
||||
|
||||
$build_target
|
||||
->setDetail('exec.leasePHID', $lease->getPHID())
|
||||
->save();
|
||||
}
|
||||
|
||||
if ($lease->isActivating()) {
|
||||
// TODO: Smart backoff?
|
||||
throw new PhabricatorWorkerYieldException(15);
|
||||
}
|
||||
|
||||
if (!$lease->isActive()) {
|
||||
// TODO: We could just forget about this lease and retry?
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
pht(
|
||||
'Lease "%s" never activated.',
|
||||
$lease->getPHID()));
|
||||
}
|
||||
|
||||
$artifact = $build_target->createArtifact(
|
||||
$viewer,
|
||||
$settings['name'],
|
||||
HarbormasterWorkingCopyArtifact::ARTIFACTCONST,
|
||||
array(
|
||||
'drydockLeasePHID' => $lease->getPHID(),
|
||||
));
|
||||
}
|
||||
|
||||
public function getArtifactOutputs() {
|
||||
return array(
|
||||
array(
|
||||
'name' => pht('Working Copy'),
|
||||
'key' => $this->getSetting('name'),
|
||||
'type' => HarbormasterHostArtifact::ARTIFACTCONST,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFieldSpecifications() {
|
||||
return array(
|
||||
'name' => array(
|
||||
'name' => pht('Artifact Name'),
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -251,6 +251,7 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||
'buildable.revision' => null,
|
||||
'buildable.commit' => null,
|
||||
'repository.callsign' => null,
|
||||
'repository.phid' => null,
|
||||
'repository.vcs' => null,
|
||||
'repository.uri' => null,
|
||||
'step.timestamp' => null,
|
||||
|
|
|
@ -332,6 +332,7 @@ final class PhabricatorRepositoryCommit
|
|||
$repo = $this->getRepository();
|
||||
|
||||
$results['repository.callsign'] = $repo->getCallsign();
|
||||
$results['repository.phid'] = $repo->getPHID();
|
||||
$results['repository.vcs'] = $repo->getVersionControlSystem();
|
||||
$results['repository.uri'] = $repo->getPublicCloneURI();
|
||||
|
||||
|
@ -343,6 +344,8 @@ final class PhabricatorRepositoryCommit
|
|||
'buildable.commit' => pht('The commit identifier, if applicable.'),
|
||||
'repository.callsign' =>
|
||||
pht('The callsign of the repository in Phabricator.'),
|
||||
'repository.phid' =>
|
||||
pht('The PHID of the repository in Phabricator.'),
|
||||
'repository.vcs' =>
|
||||
pht('The version control system, either "svn", "hg" or "git".'),
|
||||
'repository.uri' =>
|
||||
|
|
Loading…
Reference in a new issue