diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5cc4d58561..d6662ebfa8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -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', diff --git a/src/applications/differential/storage/DifferentialDiff.php b/src/applications/differential/storage/DifferentialDiff.php index 7a5bc24203..25421bafe6 100644 --- a/src/applications/differential/storage/DifferentialDiff.php +++ b/src/applications/differential/storage/DifferentialDiff.php @@ -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' => diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php index afe618c77e..fe38f54fe0 100644 --- a/src/applications/drydock/storage/DrydockLease.php +++ b/src/applications/drydock/storage/DrydockLease.php @@ -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() { diff --git a/src/applications/drydock/view/DrydockLeaseListView.php b/src/applications/drydock/view/DrydockLeaseListView.php index 7d7d8e77ee..d3507546ad 100644 --- a/src/applications/drydock/view/DrydockLeaseListView.php +++ b/src/applications/drydock/view/DrydockLeaseListView.php @@ -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'); diff --git a/src/applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php b/src/applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php new file mode 100644 index 0000000000..bd3868e7db --- /dev/null +++ b/src/applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php @@ -0,0 +1,73 @@ + '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(); + } + +} diff --git a/src/applications/harbormaster/artifact/HarbormasterHostArtifact.php b/src/applications/harbormaster/artifact/HarbormasterHostArtifact.php index ce109eb498..1c2eec8264 100644 --- a/src/applications/harbormaster/artifact/HarbormasterHostArtifact.php +++ b/src/applications/harbormaster/artifact/HarbormasterHostArtifact.php @@ -1,6 +1,7 @@ '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(); - } - } diff --git a/src/applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php b/src/applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php new file mode 100644 index 0000000000..84ce403124 --- /dev/null +++ b/src/applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php @@ -0,0 +1,16 @@ +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, + ), + ); + } + +} diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuild.php b/src/applications/harbormaster/storage/build/HarbormasterBuild.php index bcbd5e0961..1c012b1842 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuild.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuild.php @@ -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, diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index 984e6325f7..531bac9dad 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -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' =>