@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+225 -74
+7 -1
src/__phutil_library_map__.php
··· 1002 1002 'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', 1003 1003 'HarbormasterCreateArtifactConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterCreateArtifactConduitAPIMethod.php', 1004 1004 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 1005 + 'HarbormasterDrydockLeaseArtifact' => 'applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php', 1005 1006 'HarbormasterExternalBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterExternalBuildStepGroup.php', 1006 1007 'HarbormasterFileArtifact' => 'applications/harbormaster/artifact/HarbormasterFileArtifact.php', 1007 1008 'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', 1008 1009 'HarbormasterHostArtifact' => 'applications/harbormaster/artifact/HarbormasterHostArtifact.php', 1009 1010 'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php', 1011 + 'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php', 1010 1012 'HarbormasterLintMessagesController' => 'applications/harbormaster/controller/HarbormasterLintMessagesController.php', 1011 1013 'HarbormasterLintPropertyView' => 'applications/harbormaster/view/HarbormasterLintPropertyView.php', 1012 1014 'HarbormasterManagePlansCapability' => 'applications/harbormaster/capability/HarbormasterManagePlansCapability.php', ··· 1047 1049 'HarbormasterUploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php', 1048 1050 'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php', 1049 1051 'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php', 1052 + 'HarbormasterWorkingCopyArtifact' => 'applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php', 1050 1053 'HeraldAction' => 'applications/herald/action/HeraldAction.php', 1051 1054 'HeraldActionGroup' => 'applications/herald/action/HeraldActionGroup.php', 1052 1055 'HeraldActionRecord' => 'applications/herald/storage/HeraldActionRecord.php', ··· 4786 4789 'HarbormasterController' => 'PhabricatorController', 4787 4790 'HarbormasterCreateArtifactConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 4788 4791 'HarbormasterDAO' => 'PhabricatorLiskDAO', 4792 + 'HarbormasterDrydockLeaseArtifact' => 'HarbormasterArtifact', 4789 4793 'HarbormasterExternalBuildStepGroup' => 'HarbormasterBuildStepGroup', 4790 4794 'HarbormasterFileArtifact' => 'HarbormasterArtifact', 4791 4795 'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4792 - 'HarbormasterHostArtifact' => 'HarbormasterArtifact', 4796 + 'HarbormasterHostArtifact' => 'HarbormasterDrydockLeaseArtifact', 4793 4797 'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4798 + 'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4794 4799 'HarbormasterLintMessagesController' => 'HarbormasterController', 4795 4800 'HarbormasterLintPropertyView' => 'AphrontView', 4796 4801 'HarbormasterManagePlansCapability' => 'PhabricatorPolicyCapability', ··· 4831 4836 'HarbormasterUploadArtifactBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4832 4837 'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4833 4838 'HarbormasterWorker' => 'PhabricatorWorker', 4839 + 'HarbormasterWorkingCopyArtifact' => 'HarbormasterDrydockLeaseArtifact', 4834 4840 'HeraldAction' => 'Phobject', 4835 4841 'HeraldActionGroup' => 'HeraldGroup', 4836 4842 'HeraldActionRecord' => 'HeraldDAO',
+3
src/applications/differential/storage/DifferentialDiff.php
··· 443 443 444 444 if ($repo) { 445 445 $results['repository.callsign'] = $repo->getCallsign(); 446 + $results['repository.phid'] = $repo->getPHID(); 446 447 $results['repository.vcs'] = $repo->getVersionControlSystem(); 447 448 $results['repository.uri'] = $repo->getPublicCloneURI(); 448 449 } ··· 459 460 pht('The differential revision ID, if applicable.'), 460 461 'repository.callsign' => 461 462 pht('The callsign of the repository in Phabricator.'), 463 + 'repository.phid' => 464 + pht('The PHID of the repository in Phabricator.'), 462 465 'repository.vcs' => 463 466 pht('The version control system, either "svn", "hg" or "git".'), 464 467 'repository.uri' =>
+10 -9
src/applications/drydock/storage/DrydockLease.php
··· 126 126 return $this; 127 127 } 128 128 129 - public function isActive() { 130 - switch ($this->status) { 129 + public function isActivating() { 130 + switch ($this->getStatus()) { 131 + case DrydockLeaseStatus::STATUS_PENDING: 131 132 case DrydockLeaseStatus::STATUS_ACQUIRED: 132 - case DrydockLeaseStatus::STATUS_ACTIVE: 133 133 return true; 134 134 } 135 + 135 136 return false; 136 137 } 137 138 138 - private function assertActive() { 139 - if (!$this->isActive()) { 140 - throw new Exception( 141 - pht( 142 - 'Lease is not active! You can not interact with resources through '. 143 - 'an inactive lease.')); 139 + public function isActive() { 140 + switch ($this->getStatus()) { 141 + case DrydockLeaseStatus::STATUS_ACTIVE: 142 + return true; 144 143 } 144 + 145 + return false; 145 146 } 146 147 147 148 public function waitUntilActive() {
+4 -1
src/applications/drydock/view/DrydockLeaseListView.php
··· 41 41 $item->addAttribute($status); 42 42 $item->setEpoch($lease->getDateCreated()); 43 43 44 - if ($lease->isActive()) { 44 + // TODO: Tailor this for clarity. 45 + if ($lease->isActivating()) { 46 + $item->setStatusIcon('fa-dot-circle-o yellow'); 47 + } else if ($lease->isActive()) { 45 48 $item->setStatusIcon('fa-dot-circle-o green'); 46 49 } else { 47 50 $item->setStatusIcon('fa-dot-circle-o red');
+73
src/applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php
··· 1 + <?php 2 + 3 + abstract class HarbormasterDrydockLeaseArtifact 4 + extends HarbormasterArtifact { 5 + 6 + public function getArtifactParameterSpecification() { 7 + return array( 8 + 'drydockLeasePHID' => 'string', 9 + ); 10 + } 11 + 12 + public function getArtifactParameterDescriptions() { 13 + return array( 14 + 'drydockLeasePHID' => pht( 15 + 'Drydock working copy lease to create an artifact from.'), 16 + ); 17 + } 18 + 19 + public function getArtifactDataExample() { 20 + return array( 21 + 'drydockLeasePHID' => 'PHID-DRYL-abcdefghijklmnopqrst', 22 + ); 23 + } 24 + 25 + public function renderArtifactSummary(PhabricatorUser $viewer) { 26 + $artifact = $this->getBuildArtifact(); 27 + $lease_phid = $artifact->getProperty('drydockLeasePHID'); 28 + return $viewer->renderHandle($lease_phid); 29 + } 30 + 31 + public function willCreateArtifact(PhabricatorUser $actor) { 32 + $this->loadArtifactLease($actor); 33 + } 34 + 35 + public function loadArtifactLease(PhabricatorUser $viewer) { 36 + $artifact = $this->getBuildArtifact(); 37 + $lease_phid = $artifact->getProperty('drydockLeasePHID'); 38 + 39 + $lease = id(new DrydockLeaseQuery()) 40 + ->setViewer($viewer) 41 + ->withPHIDs(array($lease_phid)) 42 + ->executeOne(); 43 + if (!$lease) { 44 + throw new Exception( 45 + pht( 46 + 'Drydock lease PHID "%s" does not correspond to a valid lease.', 47 + $lease_phid)); 48 + } 49 + 50 + return $lease; 51 + } 52 + 53 + public function releaseArtifact(PhabricatorUser $actor) { 54 + $lease = $this->loadArtifactLease($actor); 55 + if (!$lease->canRelease()) { 56 + return; 57 + } 58 + 59 + $author_phid = $actor->getPHID(); 60 + if (!$author_phid) { 61 + $author_phid = id(new PhabricatorHarbormasterApplication())->getPHID(); 62 + } 63 + 64 + $command = DrydockCommand::initializeNewCommand($actor) 65 + ->setTargetPHID($lease->getPHID()) 66 + ->setAuthorPHID($author_phid) 67 + ->setCommand(DrydockCommand::COMMAND_RELEASE) 68 + ->save(); 69 + 70 + $lease->scheduleUpdate(); 71 + } 72 + 73 + }
+2 -63
src/applications/harbormaster/artifact/HarbormasterHostArtifact.php
··· 1 1 <?php 2 2 3 - final class HarbormasterHostArtifact extends HarbormasterArtifact { 3 + final class HarbormasterHostArtifact 4 + extends HarbormasterDrydockLeaseArtifact { 4 5 5 6 const ARTIFACTCONST = 'host'; 6 7 ··· 10 11 11 12 public function getArtifactTypeDescription() { 12 13 return pht('References a host lease from Drydock.'); 13 - } 14 - 15 - 16 - public function getArtifactParameterSpecification() { 17 - return array( 18 - 'drydockLeasePHID' => 'string', 19 - ); 20 - } 21 - 22 - public function getArtifactParameterDescriptions() { 23 - return array( 24 - 'drydockLeasePHID' => pht( 25 - 'Drydock host lease to create an artifact from.'), 26 - ); 27 - } 28 - 29 - public function getArtifactDataExample() { 30 - return array( 31 - 'drydockLeasePHID' => 'PHID-DRYL-abcdefghijklmnopqrst', 32 - ); 33 - } 34 - 35 - public function renderArtifactSummary(PhabricatorUser $viewer) { 36 - $artifact = $this->getBuildArtifact(); 37 - $file_phid = $artifact->getProperty('drydockLeasePHID'); 38 - return $viewer->renderHandle($file_phid); 39 - } 40 - 41 - public function willCreateArtifact(PhabricatorUser $actor) { 42 - $this->loadArtifactLease($actor); 43 - } 44 - 45 - public function loadArtifactLease(PhabricatorUser $viewer) { 46 - $artifact = $this->getBuildArtifact(); 47 - $lease_phid = $artifact->getProperty('drydockLeasePHID'); 48 - 49 - $lease = id(new DrydockLeaseQuery()) 50 - ->setViewer($viewer) 51 - ->withPHIDs(array($lease_phid)) 52 - ->executeOne(); 53 - if (!$lease) { 54 - throw new Exception( 55 - pht( 56 - 'Drydock lease PHID "%s" does not correspond to a valid lease.', 57 - $lease_phid)); 58 - } 59 - 60 - return $lease; 61 - } 62 - 63 - public function releaseArtifact(PhabricatorUser $actor) { 64 - $lease = $this->loadArtifactLease($actor); 65 - if (!$lease->canRelease()) { 66 - return; 67 - } 68 - 69 - $command = DrydockCommand::initializeNewCommand($actor) 70 - ->setTargetPHID($lease->getPHID()) 71 - ->setCommand(DrydockCommand::COMMAND_RELEASE) 72 - ->save(); 73 - 74 - $lease->scheduleUpdate(); 75 14 } 76 15 77 16 }
+16
src/applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php
··· 1 + <?php 2 + 3 + final class HarbormasterWorkingCopyArtifact 4 + extends HarbormasterDrydockLeaseArtifact { 5 + 6 + const ARTIFACTCONST = 'working-copy'; 7 + 8 + public function getArtifactTypeName() { 9 + return pht('Drydock Working Copy'); 10 + } 11 + 12 + public function getArtifactTypeDescription() { 13 + return pht('References a working copy lease from Drydock.'); 14 + } 15 + 16 + }
+106
src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
··· 1 + <?php 2 + 3 + final class HarbormasterLeaseWorkingCopyBuildStepImplementation 4 + extends HarbormasterBuildStepImplementation { 5 + 6 + public function getName() { 7 + return pht('Lease Working Copy'); 8 + } 9 + 10 + public function getGenericDescription() { 11 + return pht('Build a working copy in Drydock.'); 12 + } 13 + 14 + public function getBuildStepGroupKey() { 15 + return HarbormasterPrototypeBuildStepGroup::GROUPKEY; 16 + } 17 + 18 + public function execute( 19 + HarbormasterBuild $build, 20 + HarbormasterBuildTarget $build_target) { 21 + $viewer = PhabricatorUser::getOmnipotentUser(); 22 + 23 + $settings = $this->getSettings(); 24 + 25 + // TODO: We should probably have a separate temporary storage area for 26 + // execution stuff that doesn't step on configuration state? 27 + $lease_phid = $build_target->getDetail('exec.leasePHID'); 28 + 29 + if ($lease_phid) { 30 + $lease = id(new DrydockLeaseQuery()) 31 + ->setViewer($viewer) 32 + ->withPHIDs(array($lease_phid)) 33 + ->executeOne(); 34 + if (!$lease) { 35 + throw new PhabricatorWorkerPermanentFailureException( 36 + pht( 37 + 'Lease "%s" could not be loaded.', 38 + $lease_phid)); 39 + } 40 + } else { 41 + $working_copy_type = id(new DrydockWorkingCopyBlueprintImplementation()) 42 + ->getType(); 43 + 44 + $lease = id(new DrydockLease()) 45 + ->setResourceType($working_copy_type) 46 + ->setOwnerPHID($build_target->getPHID()); 47 + 48 + $variables = $build_target->getVariables(); 49 + 50 + $repository_phid = idx($variables, 'repository.phid'); 51 + $commit = idx($variables, 'repository.commit'); 52 + 53 + $lease 54 + ->setAttribute('repositoryPHID', $repository_phid) 55 + ->setAttribute('commit', $commit); 56 + 57 + $lease->queueForActivation(); 58 + 59 + $build_target 60 + ->setDetail('exec.leasePHID', $lease->getPHID()) 61 + ->save(); 62 + } 63 + 64 + if ($lease->isActivating()) { 65 + // TODO: Smart backoff? 66 + throw new PhabricatorWorkerYieldException(15); 67 + } 68 + 69 + if (!$lease->isActive()) { 70 + // TODO: We could just forget about this lease and retry? 71 + throw new PhabricatorWorkerPermanentFailureException( 72 + pht( 73 + 'Lease "%s" never activated.', 74 + $lease->getPHID())); 75 + } 76 + 77 + $artifact = $build_target->createArtifact( 78 + $viewer, 79 + $settings['name'], 80 + HarbormasterWorkingCopyArtifact::ARTIFACTCONST, 81 + array( 82 + 'drydockLeasePHID' => $lease->getPHID(), 83 + )); 84 + } 85 + 86 + public function getArtifactOutputs() { 87 + return array( 88 + array( 89 + 'name' => pht('Working Copy'), 90 + 'key' => $this->getSetting('name'), 91 + 'type' => HarbormasterHostArtifact::ARTIFACTCONST, 92 + ), 93 + ); 94 + } 95 + 96 + public function getFieldSpecifications() { 97 + return array( 98 + 'name' => array( 99 + 'name' => pht('Artifact Name'), 100 + 'type' => 'text', 101 + 'required' => true, 102 + ), 103 + ); 104 + } 105 + 106 + }
+1
src/applications/harbormaster/storage/build/HarbormasterBuild.php
··· 251 251 'buildable.revision' => null, 252 252 'buildable.commit' => null, 253 253 'repository.callsign' => null, 254 + 'repository.phid' => null, 254 255 'repository.vcs' => null, 255 256 'repository.uri' => null, 256 257 'step.timestamp' => null,
+3
src/applications/repository/storage/PhabricatorRepositoryCommit.php
··· 332 332 $repo = $this->getRepository(); 333 333 334 334 $results['repository.callsign'] = $repo->getCallsign(); 335 + $results['repository.phid'] = $repo->getPHID(); 335 336 $results['repository.vcs'] = $repo->getVersionControlSystem(); 336 337 $results['repository.uri'] = $repo->getPublicCloneURI(); 337 338 ··· 343 344 'buildable.commit' => pht('The commit identifier, if applicable.'), 344 345 'repository.callsign' => 345 346 pht('The callsign of the repository in Phabricator.'), 347 + 'repository.phid' => 348 + pht('The PHID of the repository in Phabricator.'), 346 349 'repository.vcs' => 347 350 pht('The version control system, either "svn", "hg" or "git".'), 348 351 'repository.uri' =>